maborak.com~/blog/argo-cd-october-2026-security-releasessoftware & infrastructure engineering
Back to all articles

Argo CD October 2026: eight advisories, then a compromised root CA in the images

Argo CD 3.3.15, 3.4.10 and 3.5.4 fix four critical repo-server and AppProject flaws. Only 3.3.18, 3.4.12 and 3.5.6 also drop the compromised eMudhra root from the image.

By the Maborak engineering team · · 9 min read

Argo CD published eight security advisories on 7 October 2026, four of them rated 9.9 Critical, fixed in 3.3.15, 3.4.10 and 3.5.4. Two weeks later the eMudhra certificate authority was shown to be compromised, and the Argo CD container images carried one of its roots in their trust store. The releases that fix both are 3.3.18, 3.4.12 and 3.5.6, and only one of the three release notes says so.

Checked 29 October 2026. Versions, affected ranges and workarounds are from the GitHub security advisories, release notes and pull requests linked under Sources. The trust-store results were measured on the published quay.io/argoproj/argocd images on this machine.

Background

The October batch was published on 7 October, alongside 3.3.15, 3.4.10, 3.5.4 and 3.6.0-rc2 (released on 6 October). Every advisory states that every supported release was affected, and that 3.0 through 3.2 are out of support and get no patch. Several of the flaws are old: the Jsonnet import issue dates from v0.9.0 (2018), the Kustomize Helm issue from v2.1.0 (2021).

Advisory CVSS Component Introduced
GHSA-m3vr-7329-44ww (CVE-2026-113672) 9.9 Jsonnet import reads repo-server files v0.9.0
GHSA-fw5c-w8rc-j7fx (CVE-2026-113709) 9.9 Kustomize helmGlobals.configHome runs a plugin v2.1.0
GHSA-9v9p-x54c-58gc (CVE-2026-113708) 9.9 Kustomize remote ref parsed as a Git option v2.7.0
GHSA-fmxq-cgp8-87wp (CVE-2026-77459) 9.9 PreDelete/PostDelete hooks skip AppProject checks v2.10.0
GHSA-j6cw-g6p4-7hch (CVE-2026-55797) 8.8 SSH repository proxy URL reaches a shell v2.11.0
GHSA-4439-h7jw-5cjj (CVE-2025-61560) 7.5 Local login failure limit races v1.5.3
GHSA-w996-f2wq-x9c6 6.5 Unbounded OCI manifest read v3.1.0
GHSA-g3ff-q88g-chrj 4.9 Extension proxy RBAC drops the app namespace v2.7.0

On 20 October the eMudhra CA’s private keys were shown to be compromised. Canonical shipped ca-certificates 20260816 the same day. Argo CD 3.4 and 3.5 images are built on Ubuntu 26.04, so the 3.4.12 and 3.5.6 rebuilds on 20 October picked up the fix. Argo CD 3.3 images are built on Ubuntu 25.10, which no longer receives updates. Pull request #30349 (merged 22 October, shipped in 3.3.18) disables the root by hand.

Mechanics

Four of the critical flaws share one property: a manifest source that a Git committer controls makes argocd-repo-server do something outside the repository.

  • Jsonnet. The importer opens any path the process can read. The search list applies only to relative imports, so import "/proc/self/environ", a ../ path or a symlink out of the repository is read with the repo-server’s permissions. Putting the contents in a ConfigMap returns them through the rendered manifest, because only Secrets are redacted. [vendor]
  • Kustomize remote ref. Kustomize builds git fetch <url> <ref> with no -- separator. A ref beginning with --upload-pack= becomes a Git option, and Git runs it for a file:// remote. The command output comes back in the manifest-generation error. [vendor]
  • Kustomize Helm. With --enable-helm, helmGlobals.configHome is copied into Helm’s config home, and Helm loads a downloader plugin from <configHome>/.data/plugins without an install step. [vendor]
  • Delete hooks. Sync hooks pass the AppProject destination and resource checks. PreDelete and PostDelete hooks are created with the application-controller’s credentials and never pass through that check. [vendor]

The fixes put the boundary back where it belongs. Jsonnet imports are resolved, symlinks included, and rejected outside the repository root. Kustomize builds get a git wrapper on PATH that stops URLs and refs from being parsed as options. Helm runs with an empty config home. Delete hooks go through the same project check as sync. [vendor]

The CA issue is a different invariant: the trust store in an image is frozen when the image is built. Git, Helm and Kustomize inside the repo-server validate TLS against /etc/ssl/certs. The 3.3 fix is one line in the Dockerfile:

sed -i 's@^mozilla/emSign_ECC_Root_CA_-_G3.crt@!&@' /etc/ca-certificates.conf && update-ca-certificates

Impact

The advisories. The four critical issues need someone who can push to a Git repository that an Application builds. The Jsonnet and Kustomize issues can also be reached by anyone allowed to upload files to POST /api/v1/applications/manifestsWithFiles. On a default install, Jsonnet and Kustomize remote bases are enabled, so committer access to an application repository becomes code execution or file read as the repo-server. That process holds the Git, Helm and OCI credentials for every repository Argo CD knows. The Kustomize Helm issue needs --enable-helm set by an operator. The delete-hook issue runs when someone deletes the Application, using the controller’s cluster access. The login-limit race needs no account at all: it applies to local accounts, including admin when it is enabled, but not to SSO. [vendor]

The CA. A TLS client that trusts a compromised root accepts a certificate the attacker signs for any host. For the repo-server, that means an attacker-in-the-middle can serve Git, Helm or OCI content as if it came from the real host. Images built before the Ubuntu fix, or built on 25.10 without the sed, trust the root. The probe below shows which ones.

Probe

The probe pulls Argo CD images and lists, for each one, the base OS, the ca-certificates version and every trusted eMudhra or Comodo AAA root. It reads files only. Environment: Docker 29.9.2 on macOS, images from quay.io/argoproj/argocd, run with --entrypoint sh so no Argo CD process starts.

#!/bin/sh
# usage: ./argocd-ca-probe.sh v3.3.17 v3.3.18 ...
for tag in "$@"; do
  img="quay.io/argoproj/argocd:$tag"
  docker pull -q "$img" >/dev/null || { echo "$tag: pull failed"; continue; }
  docker run --rm --entrypoint sh "$img" -c '
    . /etc/os-release
    printf "%-9s %-28s ca-certificates %s\n" "'"$tag"'" "$PRETTY_NAME" "$(dpkg-query -W -f="\${Version}" ca-certificates)"
    for f in /etc/ssl/certs/*.pem; do
      s=$(openssl x509 -in "$f" -noout -subject 2>/dev/null)
      case "$s" in *emSign*|*"AAA Certificate"*) echo "          trusted: ${s#subject=}";; esac
    done'
done

Output, pruned to the G3 line for brevity on the last two tags: [reproduced]

v3.3.17   Ubuntu 25.10                 ca-certificates 20260601~25.10.1
          trusted: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign ECC Root CA - C3
          trusted: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign ECC Root CA - G3
          trusted: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign Root CA - C1
          trusted: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign Root CA - G1
v3.3.18   Ubuntu 25.10                 ca-certificates 20260601~25.10.1
          trusted: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign ECC Root CA - C3
          trusted: C=US, OU=emSign PKI, O=eMudhra Inc, CN=emSign Root CA - C1
          trusted: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign Root CA - G1
v3.4.12   Ubuntu 26.04.1 LTS           ca-certificates 20260816ubuntu0.26.04.1
          (C3, C1, G1 trusted; no G3)
v3.5.6    Ubuntu 26.04.1 LTS           ca-certificates 20260816ubuntu0.26.04.1
          (C3, C1, G1 trusted; no G3)
v3.4.11   Ubuntu 26.04.1 LTS           ca-certificates 20260601~26.04.1
          trusted: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign ECC Root CA - G3
v3.5.5    Ubuntu 26.04.1 LTS           ca-certificates 20260601~26.04.1
          trusted: C=IN, OU=emSign PKI, O=eMudhra Technologies Limited, CN=emSign ECC Root CA - G3

Three results follow from this.

  1. The 3.3.18 change works: the same Ubuntu 25.10 package, with emSign ECC Root CA – G3 no longer trusted.
  2. 3.4.12 and 3.5.6 are fixed with no line about it in their release notes. The fix came from the base image’s ca-certificates. 3.4.11 and 3.5.5, released on 12 October, still trust G3.
  3. Canonical’s notice says “emSign Root TLS CA – G3” was removed. That certificate is real: it is a root only in Microsoft’s store, and in these bundles it is reached through a cross-certificate signed by emSign ECC Root CA – G3. The bundle entry that changed is ECC G3, the same root Argo CD’s sed disables, and removing it breaks the chain through emSign Root TLS CA – G3 as well. The eMudhra post shows both chains. Corrected 29 October 2026: an earlier version said no certificate with that name exists. The other three emSign roots stay trusted in every image, including the fixed ones. No Comodo AAA root appears in any of them.

No probe for the eight advisories is included. They are remote code execution and file-read bugs, and the fix is the version. The checks under Verification show what is actually running.

Mitigation

  1. Upgrade to 3.3.18, 3.4.12 or 3.5.6. These include every 7 October fix and the CA change. 3.3.15, 3.4.10 and 3.5.4 fix the advisories but still trust G3. The 3.3 pull request says that branch “is going to go out of support very soon”, so plan a 3.4 or 3.5 move. Argo CD 3.0 through 3.2 get no patches. Read the upgrading notes before changing minor version.
  2. Configuration, until the upgrade lands. Set jsonnet.enable: "false" in argocd-cm if no Application uses Jsonnet. Remove --enable-helm from kustomize.buildOptions if nothing renders Helm through Kustomize. Disable admin and other local accounts in favour of SSO. Remove proxies from SSH repositories and credential templates. The Kustomize remote-ref issue has no complete workaround short of pinning every Application to Kustomize 4.5.7.
  3. Compensating controls. Limit who can push to repositories behind restrictive AppProjects, who can delete Applications, and who can create repositories. Narrow the default project’s sourceRepos: ['*']. Reduce the application-controller’s cluster RBAC so a hook cannot reach namespaces it should not.
  4. Custom images. An image built FROM quay.io/argoproj/argocd:v3.4.11 or older, or built from source on Ubuntu 25.10, keeps the old trust store until it is rebuilt. Add the sed line above, or rebuild on a base with ca-certificates 20260816 or later.
  5. Rollback. Moving back below 3.3.15, 3.4.10 or 3.5.4 reopens all eight advisories. If an upgrade has to be reverted, apply the workarounds in step 2 first.

Verification

A tag in a manifest is not proof that the pod runs it. Check what the cluster actually runs:

# image and digest actually running, per Argo CD component
kubectl -n argocd get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[0].imageID}{"\n"}{end}'

# server version reported by the API server
argocd version --short

# trust store inside the running repo-server: no output means G3 is not trusted
kubectl -n argocd exec deploy/argocd-repo-server -- sh -c \
  'for f in /etc/ssl/certs/*.pem; do openssl x509 -in "$f" -noout -subject; done | grep "ECC Root CA - G3"'

Compare the image digest with the one published for the release. The tested 3.5.6 image resolved to sha256:8e5cc5bb008df8a09dba439462e58c94c55b7735888d3ebde0c25fc05e4e5335 on 29 October. Argo CD images are signed with cosign; the signed-release-assets documentation shows how to check the signature and provenance.

Sources

Back to all articles

Technologies we work with

  • Argo CD
  • Kubernetes
  • Docker
  • Podman
  • Ansible
  • Jenkins
  • Chef
  • Proxmox VE
  • Google Cloud
  • Linux
  • Red Hat
  • CentOS
  • NGINX
  • Apache
  • Traefik
  • Prometheus
  • Grafana
  • PostgreSQL
  • MySQL
  • MariaDB
  • Redis
  • etcd
  • Qdrant
  • Elasticsearch
  • Logstash
  • Kibana
  • PagerDuty
  • Go
  • Python
  • FastAPI
  • PHP
  • TypeScript
  • React