Bug 2510327 (CVE-2026-18621)

Summary: CVE-2026-18621 data-sciences-pipeline: DSP: V1 Argo template path accepts arbitrary Workflow spec, bypassing all v2 security hardening
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security <prodsec-ir-bot>
Status: NEW --- QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: unspecifiedCC: alinfoot, dtrifiro, rbryant, security-response-team, weaton
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A flaw was found in Data Science Pipelines (DSP). An attacker with namespace editor privileges can bypass security hardening by submitting a malicious Argo Workflow through the V1 API path. This allows the API server to create pods with elevated privileges, acting as a 'confused deputy' on behalf of the attacker. Successful exploitation grants the attacker node-root access, enabling arbitrary code execution and full control over the underlying node.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description OSIDB Bzimport 2026-08-03 08:03:17 UTC
Finding
The v2 compiler (backend/src/v2/compiler/argocompiler/security_context.go) forcibly applies PSS-restricted defaults to every container it generates. The kubernetes_executor_config proto explicitly removed privileged/add_capabilities/drop_capabilities. All of this is bypassed when a tenant uploads a document whose TypeMeta matches argoproj.io/v1alpha1 / Workflow: the API server unmarshals it into a full workflowapi.Workflow struct and creates it via its own ServiceAccount (which holds workflows: create). The Argo workflow-controller then materializes pods containing whatever the tenant wrote: spec.templates[].container.securityContext.privileged: true, spec.hostNetwork: true, spec.hostPID: true, spec.volumes[].hostPath.path: /, arbitrary initContainers, and spec.serviceAccountName.

Files:

backend/src/apiserver/template/template.go:62-67 — inferTemplateFormat routes any V1 document

backend/src/apiserver/template/template.go:153-157 — NewArgoTemplate

backend/src/apiserver/template/argo_template.go:209-230 — ValidateWorkflow runs structural lint only, no security-context filtering

backend/src/apiserver/template/argo_template.go:30-91 — RunWorkflow deep-copies user spec verbatim

Framework: OWASP K8s K01/K02; ASVS V5.2.5
CWE: CWE-1336 (Improper Neutralization of Special Elements Used in a Template Engine) / CWE-668 (Exposure of Resource to Wrong Sphere)
CVSS v3.1: 7.6 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L) – High

Confused-Deputy Aspect
The pipeline submitter need not hold create workflows or use scc/privileged. The ml-pipeline SA creates the Workflow on their behalf, and the workflow-controller SA creates the Pod. Whether the pod is admitted depends solely on namespace SCC/PSA. In RHOAI data-science-project namespaces that bind GPU operators or anyuid/privileged SCC for CUDA workloads, this yields node-root.

Verification
Confirmed that the V1 path is still reachable in RHOAI/DSPO deployments:

DSPO passes no flags or env vars to disable V1 template handling

The Argo CRD deployed by DSPO registers v1alpha1 as served:true and storage:true

No DSPA CR field, operator config, or feature flag restricts template formats

Impact
A namespace editor can achieve node-root by uploading a raw Argo Workflow with hostPath, hostNetwork, privileged:true via the V1 API path. The API server creates the Workflow CR as a confused deputy.

Remediation
Disable the V1 Argo template path in RHOAI builds (feature flag, fail inferTemplateFormat to V1 with NewInvalidInputError)

If V1 must remain, add a sanitizer in RunWorkflow/ValidateWorkflow that strips hostPath/hostNetwork/hostPID/hostIPC, forces securityContext.privileged=false, drops capabilities, and clears serviceAccountName

Operator-side: ensure DSP namespaces carry pod-security.kubernetes.io/enforce: restricted and that pipeline-runner SA is not bound to privileged/anyuid SCC