Argo Workflows auth, resource, and secret-boundary batch (GHSA)¶
Signal: GitHub Security Advisories REST fallback surfaced six Argo Workflows advisories on 2026-05-04. The durable pattern is control-plane logic that trusted workflow, webhook, SSO, or sync input before enforcing the same authorization, size, and secret-handling invariants everywhere.
Advisories in this batch¶
- Artifact repository credentials logged in plaintext — Argo Workflows
github.com/argoproj/argo-workflows/v4>= 4.0.0, < 4.0.5logs artifact driver structs during artifact operations, exposing S3, GCS, Azure, Git, and other repository credentials to anyone with workflow pod-log read access. Fixed in 4.0.5. References: https://github.com/advisories/GHSA-7vf8-2cr6-54mf, CVE-2026-42295. - Strict/Secure template reference bypass — Argo Workflows
v3 < 3.7.14andv4 >= 4.0.0, < 4.0.5can still merge attacker-controlledhostNetwork,securityContext, orserviceAccountNamefields into pods even whentemplateReferencing: Strict/Secureis intended to enforce hardened templates. Fixed in 3.7.14 and 4.0.5. References: https://github.com/advisories/GHSA-3775-99mw-8rp4, CVE-2026-42296. - Unauthenticated webhook body memory exhaustion — Argo Workflows
v3 < 3.7.14andv4 >= 4.0.0, < 4.0.5read the full/api/v1/events/request body before authenticating or verifying signatures, allowing unauthenticated OOM denial of service. Fixed in 3.7.14 and 4.0.5. References: https://github.com/advisories/GHSA-jcc8-g2q4-9fxq, CVE-2026-42294. - Sync ConfigMap provider missing authorization — Argo Workflows
v4 >= 4.0.0, < 4.0.5allowed authenticated users, including weak/fake bearer-token paths described by the advisory, to create, read, update, or delete synchronization-limit ConfigMaps withoutauth.CanIchecks. Fixed in 4.0.5. References: https://github.com/advisories/GHSA-xchc-cqwg-g76q, CVE-2026-42297. - SSO RBAC delegation nil-pointer DoS — Argo Workflows
v4 >= 4.0.0, <= 4.0.4can panic when namespace-level RBAC matches but SSO-namespace RBAC does not whileSSO_DELEGATE_RBAC_TO_NAMESPACE=true. Fixed in 4.0.5. References: https://github.com/advisories/GHSA-p4gq-3vxj-f4jq, CVE-2026-42183.
Why this is durable¶
Workflow control planes are high-trust systems because they mint pods, mount secrets, read repositories, and broker webhooks. Small inconsistencies become large blast-radius bugs:
- Secret-bearing structs must never be logged whole.
- Template restrictions must filter every field that reaches the pod spec, not only the originally reported bypass field.
- Authentication and request-size limits must happen before body buffering or parsing.
- Authorization must wrap all resource providers, including internal sync/coordination objects.
- Optional auth objects must be treated as hostile input until nil-safe and fully authorized.
Immediate triage¶
- Inventory Argo lines: search Go modules, controller images, Helm charts, and cluster manifests for Argo Workflows v3/v4. Prioritize public Argo Servers and multi-tenant clusters.
- Patch: upgrade v3 deployments to 3.7.14+ and v4 deployments to 4.0.5+.
- Rotate leaked artifact credentials: if affected v4 workflow-executor logs were readable by users or log aggregation systems, rotate artifact repository keys and review access logs for use after workflow execution.
- Lock template references: temporarily restrict workflow creation by untrusted tenants and explicitly deny
hostNetwork, privilegedsecurityContext, and unexpectedserviceAccountNamevalues in admission policy. - Constrain webhook ingress: enforce reverse-proxy body limits and authentication/signature checks before requests reach Argo Server.
- Audit sync objects: review ConfigMaps used for synchronization limits for unexpected creates, updates, deletes, or namespace drift.
Hunt ideas¶
- Query log stores for artifact credentials, access-key patterns, GCS JSON key fragments, Azure account keys, or Git credentials emitted by workflow executor logs.
- Search workflow specs for
hostNetwork: true, unexpectedserviceAccountName, added capabilities, privileged containers, hostPath mounts, and security contexts not present in referenced templates. - Review Argo Server memory/OOM events around large requests to
/api/v1/events/. - Inspect Kubernetes audit logs for Argo service accounts writing sync ConfigMaps outside expected operator workflows.
- Correlate SSO login errors or panics with namespace RBAC delegation rules.
Durable controls¶
- Redact by construction: logging helpers should serialize explicit safe fields, not entire driver/client structs.
- Make policy final at the object that causes the side effect: pod admission, credential mount, ConfigMap write, and webhook parse paths all need local guards.
- Add negative regression tests for every field that can flow through template merges, not just the original exploit field.
- Require body-size caps before auth parsing and before app-layer buffering.
- Treat internal providers as API surfaces: every create/read/update/delete path needs authorization, audit events, and tenancy checks.
Operator lesson¶
For orchestration platforms, trace from user-controlled YAML or HTTP to the Kubernetes object or secret-bearing client. If any merge, log, or provider write skips the final authorization/redaction step, assume tenants can turn it into lateral movement or credential theft.
September 21 follow-up: the Strict/Secure allow-list fix was depth-one only — ArtifactGC.PodSpecPatch reaches the same pod-patch sink¶
GHSA-48p8-g2fx-3wwm / CVE-2026-54526 (High; fixed v4 4.0.6, v3.7.15; re-surfaced on the updated feed 2026-09-21): the allow-list that fixed CVE-2026-31892 / GHSA-3775-99mw-8rp4 (the Strict/Secure template-reference bypass above) validates WorkflowSpec user overrides with reflection over top-level fields only. ArtifactGC is allow-listed wholesale (admins legitimately let users configure artifact garbage collection), and the struct behind it (WorkflowLevelArtifactGC) carries a PodSpecPatch string that flows unmodified into util.ApplyPodSpecPatch on the artifact-GC pod — the exact strategic-merge-patch primitive the original fix closed for WorkflowSpec.PodSpecPatch. Under templateReferencing: Strict or Secure, any referenced template with an output artifact (the common case) plus submitter-supplied spec.artifactGC.strategy: OnWorkflowCompletion gets an arbitrary pod spec patch onto the GC pod: attacker image + command, privileged: true, hostPath: / volume, hostNetwork: true, and the GC pod runs with AutomountServiceAccountToken: true, so the pod holds a service-account token by default. No validation sits between sanitize and sink; the fix's own regression test file covers only the top-level PodSpecPatch field.
Durable axes¶
- Depth-one allow-lists enforce nothing. When a field is allow-listed "wholesale" by a reflection-based validator, every allow-listed field is really a subschema — enumerate its sub-fields and ask which ones are themselves patch/exec/file inputs. The bypass did not touch a single line of the patched code path; it re-entered the patched sink through an allow-listed neighbor.
- Partial-fix differential hunting: after any allow-list/sanitizer fix, list every other consumer of the same primitive (here
ApplyPodSpecPatchhas a second caller inworkflow/controller/artifact_gc.go). The advisory itself proves the grep pattern: search the codebase for every call site of the patched sink helper, not just the patched field. - Test coverage is an attack map: the fix's regression test (
merge_test.go) exercised onlyWorkflowSpec.PodSpecPatch; untested sibling fields are the first places to probe. - Validation harness without a cluster: the advisory ships self-contained Go unit tests against the shipped
workflow/utilpackage (ValidateUserOverrides+SanitizeUserWorkflowSpec+ApplyPodSpecPatchagainst a baseline pod built like the controller's) — replayable gate-1/gate-2 evidence (require.NoError(ValidateUserOverrides(...))passing on a hostile spec is itself the finding) with zero live infrastructure.
Authorized validation notes¶
- Fingerprint the controller:
kubectl get deploy workflow-controller -o yaml | grep -i templateReferencing, then version-fingerprint the server (argo version). Only 4.0.0–4.0.5 / 3.x < 3.7.15 with Strict/Secure restrictions configured are in scope. - In an approved lab cluster only, submit the shape above with an inert patch (e.g. an image pointing at your owned registry with
command: [sleep, "3600"]and a marker env var) and inspect the created artifact-GC pod spec — never hostPath mounts, hostNetwork, or privileged flags on shared infrastructure. - Evidence chain: submitted Workflow YAML → accepted-by-server confirmation → generated artifact-GC pod spec diffed against the hardened baseline. Pod-spec diff is the whole proof; no token capture or node access needed.
- Same audit question for any platform with a "user patch" or "user override" allow-list (Tekton, KubeVela, Argo CD app-of-apps, CI template engines): for each allow-listed override field, does any sub-field land on a pod-patch/exec sink, and does the validator walk it?
October 9 follow-up: Argo CD repo-server RCE — SSH repository proxy URL is interpolated into a shell ProxyCommand (CVE-2026-55797)¶
GHSA-j6cw-g6p4-7hch / CVE-2026-55797 (High 8.8; affects v2.11.0 → v2.14.21 and v3.0–3.2 (unpatched, EOL); fixed v3.3.15 / 3.4.10 / 3.5.4 / 3.6.0-rc2; introduced by the 2024 SOCKS5-proxy-for-SSH feature commit): when Argo CD clones/fetches an SSH repository that has any proxy URL configured (http, https, or socks5 set on an SSH repo all take this path), the repo-server builds a shell command embedding the proxy host/port into an SSH ProxyCommand. A proxy host containing shell metacharacters breaks out and executes in the repo-server, which holds every Git/Helm/OCI credential stored for it. Trigger surface: anyone who can create/update a repository or a repository credential template — including project-scoped repository permission, argocd repo add --proxy, or a declarative repository Secret. A credential-template proxy silently applies to every matching SSH repository without its own credentials. Execution fires on connection-test and later fetches.
Durable axes¶
- "Low-privilege" CI/CD permissions are RCE when config fields reach a shell. Project-scoped
reposcreate/update is routinely granted to app teams and bounty-safe paths; it lands the attacker inside a credential-bearing pod. On any GitOps/CI control plane, enumerate every free-text config field (proxy URL, SSH opts, extra args) and ask whether it is argv-passed or shell-interpolated — metacharacter breakout from a legitimate feature field is the oldest sink in the book and still lands in 2026. - Version fingerprint is tight and passive-observable: SOCKS5-SSH-proxy support shipped in v2.11.0 and the fix is very recent → any Argo CD ≥ 2.11 below 3.3.15 with an SSH repository + proxy field set is exposed. From an authorized recon position: does the instance accept
repo add --proxysemantics for SSH repos (UI/API field presence, version banner) — no exploitation needed to scope. - Credential-template fan-out is a persistence/blast amplifier: one poisoned template proxy re-arms on every matching repo fetch. In a lab instance you own, set an inert marker proxy value on a throwaway SSH repo, trigger a fetch (Refresh), and confirm command execution as the repo-server user; proof = marker file/exec output inside the pod, plus enumerating which mounted credentials become readable — never against a shared instance.
- Sibling-audit rule: the same fix class (stop passing host/port through a shell) applies to every connector builder — check Helm/OCI/Kustomize init containers in the repo-server for other string-interpolated command paths.