The fix for CVE-2026-31892 (commit 534f4ff) blocks podSpecPatch when templateReferencing: Strict is active, but doesn't restrict other WorkflowSpec fields that flow through the same merge path and get applied to pods. A user can set hostNetwork: true, override serviceAccountName, or change securityContext on their Workflow while referencing a hardened template -- these survive JoinWorkflowSpec and get applied at pod creation.
The check in setExecWorkflow gates on HasPodSpecPatch() only:
if woc.controller.Config.WorkflowRestrictions.MustUseReference() && woc.wf.Spec.HasPodSpecPatch() {
Everything else passes through. createWorkflowPod reads hostNetwork, securityContext, serviceAccountName, tolerations, and automountServiceAccountToken from the merged spec and applies them directly to the pod.
JoinWorkflowSpec constructs the merge target from the user's spec and applies the template as a patch -- user fields take priority. When the template doesn't explicitly set a field like hostNetwork (most won't -- false is the zero value and gets omitted), the user's true survives. For fields like securityContext and serviceAccountName, the template-level value takes precedence IF the template explicitly sets it. The bypass applies when the template relies on defaults.
Both Strict and Secure modes are affected. Secure stores the merged spec on first submission, so user overrides get baked into the stored spec and subsequent MustNotChangeSpec comparisons pass.
Steps to reproduce
Tested on v4.0.2 (the CVE-2026-31892 patched version) on kind v0.27.0 / K8s v1.35.0.
# enable strict mode
kubectl patch configmap workflow-controller-configmap -n argo --type merge \
-p '{"data":{"workflowRestrictions":"templateReferencing: Strict\n"}}'
kubectl rollout restart deployment workflow-controller -n argo
A template that lists network interfaces:
cat <<'EOF' | kubectl apply -n argo -f -
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: netcheck
spec:
entrypoint: check
templates:
- name: check
container:
image: alpine:latest
command: ["/bin/sh", "-c"]
args: ["ip addr show | grep -E '^[0-9]+:' | cut -d: -f2"]
EOF
Submit a workflow with hostNetwork: true:
cat <<'EOF' | kubectl create -n argo -f -
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: bypass-
spec:
workflowTemplateRef:
name: netcheck
hostNetwork: true
EOF
Pod gets host networking:
$ kubectl get pod -n argo -l workflows.argoproj.io/workflow=bypass-bmg9b -o jsonpath='{.items[0].spec.hostNetwork}'
true
Container without the override sees eth0@if20. With the override, the pod sees the host's full network namespace -- all veth interfaces for other containers on the node.
podSpecPatch IS correctly blocked on the same cluster:
$ kubectl get workflow patched-check-jd272 -n argo -o jsonpath='{.status.message}'
podSpecPatch is not permitted when using workflowTemplateRef with templateReferencing restriction
serviceAccountName override also works -- a workflow with serviceAccountName: argo-server creates a pod running under the argo-server SA instead of the namespace default:
$ kubectl get pod -n argo -l workflows.argoproj.io/workflow=bypass-sa-slmjs -o jsonpath='{.items[0].spec.serviceAccountName}'
argo-server
Tested in Secure mode as well -- same result. Pod created with hostNetwork: true before the workflow errors on an unrelated permission issue.
Impact
A user with create Workflow permission can bypass templateReferencing: Strict to get host network access, switch service accounts, override pod security context, add tolerations to schedule on control-plane nodes, or enable SA token mounting. This defeats the stated purpose of the feature.
The practical impact depends on what Kubernetes-level controls are in place. Clusters with PodSecurity admission or OPA/Gatekeeper would independently block some of these (like hostNetwork). Clusters that rely on Argo's Strict mode as the primary enforcement layer are fully exposed.
Fix direction
The check in setExecWorkflow should cover all WorkflowSpec fields that influence pod security posture, not just podSpecPatch. The affected fields that I confirmed in createWorkflowPod: hostNetwork, securityContext, serviceAccountName, automountServiceAccountToken, tolerations, dnsPolicy, schedulerName, hostAliases, volumes.
An alternative approach: when MustUseReference() is true, strip all user-set WorkflowSpec fields except a known-safe allowlist (entrypoint, arguments, labels, annotations) before merging. This avoids a growing denylist as new fields get added.
Affected versions
All versions supporting templateReferencing, including v4.0.2 and v3.7.11 which patched CVE-2026-31892.
References
The fix for CVE-2026-31892 (commit 534f4ff) blocks
podSpecPatchwhentemplateReferencing: Strictis active, but doesn't restrict other WorkflowSpec fields that flow through the same merge path and get applied to pods. A user can sethostNetwork: true, overrideserviceAccountName, or changesecurityContexton their Workflow while referencing a hardened template -- these surviveJoinWorkflowSpecand get applied at pod creation.The check in
setExecWorkflowgates onHasPodSpecPatch()only:Everything else passes through.
createWorkflowPodreadshostNetwork,securityContext,serviceAccountName,tolerations, andautomountServiceAccountTokenfrom the merged spec and applies them directly to the pod.JoinWorkflowSpecconstructs the merge target from the user's spec and applies the template as a patch -- user fields take priority. When the template doesn't explicitly set a field likehostNetwork(most won't --falseis the zero value and gets omitted), the user'struesurvives. For fields likesecurityContextandserviceAccountName, the template-level value takes precedence IF the template explicitly sets it. The bypass applies when the template relies on defaults.Both
StrictandSecuremodes are affected.Securestores the merged spec on first submission, so user overrides get baked into the stored spec and subsequentMustNotChangeSpeccomparisons pass.Steps to reproduce
Tested on v4.0.2 (the CVE-2026-31892 patched version) on kind v0.27.0 / K8s v1.35.0.
A template that lists network interfaces:
Submit a workflow with
hostNetwork: true:Pod gets host networking:
Container without the override sees
eth0@if20. With the override, the pod sees the host's full network namespace -- all veth interfaces for other containers on the node.podSpecPatchIS correctly blocked on the same cluster:serviceAccountNameoverride also works -- a workflow withserviceAccountName: argo-servercreates a pod running under theargo-serverSA instead of the namespace default:Tested in Secure mode as well -- same result. Pod created with
hostNetwork: truebefore the workflow errors on an unrelated permission issue.Impact
A user with
create Workflowpermission can bypasstemplateReferencing: Strictto get host network access, switch service accounts, override pod security context, add tolerations to schedule on control-plane nodes, or enable SA token mounting. This defeats the stated purpose of the feature.The practical impact depends on what Kubernetes-level controls are in place. Clusters with PodSecurity admission or OPA/Gatekeeper would independently block some of these (like
hostNetwork). Clusters that rely on Argo's Strict mode as the primary enforcement layer are fully exposed.Fix direction
The check in
setExecWorkflowshould cover all WorkflowSpec fields that influence pod security posture, not justpodSpecPatch. The affected fields that I confirmed increateWorkflowPod:hostNetwork,securityContext,serviceAccountName,automountServiceAccountToken,tolerations,dnsPolicy,schedulerName,hostAliases,volumes.An alternative approach: when
MustUseReference()is true, strip all user-set WorkflowSpec fields except a known-safe allowlist (entrypoint, arguments, labels, annotations) before merging. This avoids a growing denylist as new fields get added.Affected versions
All versions supporting
templateReferencing, including v4.0.2 and v3.7.11 which patched CVE-2026-31892.References