cert-manager: Direct ACME Challenge resources can bypass Issuer DNS01 solver policy and use ClusterIssuer DNS credentials
CVE-2026-62290 · GHSA-8rvj-mm4h-c258 · published 29 Oct 2026
How serious is it
- Severity: high, CVSS score 7.3 out of 10.
- No exploit prediction (EPSS) score yet.
- Not on the CISA list of exploited vulnerabilities.
- No public exploit in Exploit-DB.
Is your app affected by CVE-2026-62290?
Paste this prompt into Claude Code, Cursor or any AI coding tool: it runs a free Shippable scan of your project and fixes what it finds. Built with Lovable, Bolt or v0? Scan your live app. Or upload your package file.
Who is affected
github.com/cert-manager/cert-manager(Go) >= 1.18.0, < 1.19.6github.com/cert-manager/cert-manager(Go) >= 1.20.0-alpha.0, < 1.20.3
How to check
- Run
go list -m github.com/cert-manager/cert-managerin your project to see the installed version, including copies pulled in by other packages. - Or paste your lockfile into the checker: it lists every package with a known vulnerability, this one included.
How to fix
Copies a prompt for Claude Code, Cursor or Codex: it checks your lockfiles for this and upgrades it.
- On >= 1.18.0, < 1.19.6: Upgrade
github.com/cert-manager/cert-managerto 1.19.6 or later, commit the lockfile and redeploy. - On >= 1.20.0-alpha.0, < 1.20.3: Upgrade
github.com/cert-manager/cert-managerto 1.20.3 or later, commit the lockfile and redeploy. - If a vulnerable version was live, check your logs and rotate the secrets that server could read.
The advisory
## Summary
`Challenge` resources under `acme.cert-manager.io` can be created directly by namespace users. On create, cert-manager performs no admission validation tying the Challenge to an `Order`, an owner reference, or an Issuer-selected solver. The ACME Challenge controller then reconciles the direct resource and uses `Challenge.spec.solver` as the DNS01 provider configuration.
When the direct Challenge references a `ClusterIssuer`, cert-manager derives the DNS provider secret namespace and ambient-credential policy from the `ClusterIssuer` reference, but the DNS provider configuration itself is attacker-controlled through `Challenge.spec.solver`. This lets a namespace user bypass `Issuer`/`ClusterIssuer` solver selectors such as `dnsZones`, `dnsNames`, and `matchLabels`, and make the cert-manager controller use ClusterIssuer DNS credentials for attacker-selected provider settings and DNS names.
In the acme-dns case, this becomes credential disclosure because the attacker-controlled solver host receives the `X-Api-User` and `X-Api-Key` headers loaded by cert-manager from the ClusterIssuer resource namespace.
## Attack preconditions
- The attacker can create `challenges.acme.cert-manager.io` resources in at least one namespace.
- The cert-manager controller is running and reconciles ACME `Challenge` resources cluster-wide.
- A usable `ClusterIssuer` exists in the cluster.
- The referenced `ClusterIssuer` has a DNS01 solver that uses a Secret in the cluster resource namespace, or relies on ambient credentials enabled for `ClusterIssuer`.
- The cluster is multi-tenant or otherwise separates namespace users from platform-owned Issuer/ClusterIssuer and DNS credential administration.
## Severity
Rationale: a tenant with namespace-level ACME Challenge create permissions, including permissions granted by cert-manager's aggregate edit role, can cause a cluster-scoped controller to use DNS credentials or ambient cloud credentials outside the Issuer's intended solver policy. With acme-dns specifically, this can disclose the referenced acme-dns account credential to an attacker-controlled endpoint. With other DNS providers, the impact is credential use, Issuer policy bypass, and unauthorized DNS mutation risk unless a provider-specific credential disclosure path is separately demonstrated.
## Why this is not just RBAC misconfiguration
cert-manager's documented end-user workflow does not require users to manually create `Challenge` resources. Challenges are internal ACME workflow objects generated from Orders after cert-manager has selected a solver from the referenced Issuer or ClusterIssuer. If default or aggregate roles grant namespace users permission to create these resources, the controller still should not treat a user-controlled `Challenge.spec.solver` as authoritative for a referenced `ClusterIssuer`.
The security boundary is the Issuer/ClusterIssuer solver policy and credential configuration. Direct Challenge creation bypasses that boundary because the controller derives credential namespace and ambient credential permission from `issuerRef`, while accepting the DNS provider configuration from the untrusted Challenge object.
## Affected components
- ACME Challenge admission validation
- ACME Challenge controller
- DNS01 solver selection and DNS provider construction
- Default aggregate RBAC for `challenges.acme.cert-manager.io`
## Affected versions tested
The issue was reproduced on:
- `master` commit `2c0f1a6a4`
- latest production release `v1.20.2` commit `e5b7b1845`
- `v1.19.5` commit `cda7b7896`
- `v1.18.6` commit `4699caabb`
See `VERSION_TEST_MATRIX.md` for the command matrix and outputs.
## Technical details
Relevant code paths:
- `internal/apis/acme/validation/challenge.go:44-45`: `ValidateChallenge` returns no errors on create.
- `deploy/crds/acme.cert-manager.io_challenges.yaml`: `spec.solver` is a required user-controlled field on `Challenge`.
- `pkg/controller/acmechallenges/scheduler/scheduler.go:51-58`: scheduler lists all Challenges.
- `pkg/controller/acmechallenges/controller.go:180-197`: scheduler sets `status.processing=true`.
- `pkg/controller/acmechallenges/sync.go:139-183`: controller loads the referenced Issuer and then presents the Challenge.
- `pkg/issuer/acme/dns/dns.go:81`: DNS solver `Present` ignores the issuer object argument.
- `pkg/issuer/acme/dns/dns.go:180-187`: DNS provider config and resource namespace are derived from `Challenge.spec`.
- `pkg/controller/helper.go:39-44`: `ClusterIssuer` references use the cluster resource namespace.
- `pkg/controller/helper.go:66-72`: ambient credentials are allowed based on `issuerRef.kind`.
- `internal/apis/config/controller/v1alpha1/defaults.go:68-69`: ClusterIssuer ambient credentials default to enabled.
- `deploy/charts/cert-manager/templates/rbac.yaml:517-519`: the aggregate edit role can create/update `challenges` and `orders`.
The normal `Order` flow selects a solver from the Issuer:
- `pkg/util/solverpicker/solverpicker.go`: solver selectors are evaluated.
- `pkg/controller/acmeorders/util.go:94-106`: solvers are fetched from the Issuer and selected.
- `pkg/controller/acmeorders/util.go:131-142`: the selected solver is copied into the generated Challenge.
The direct `Challenge` flow skips that selection entirely because the direct object already contains a solver.
## Proof of concept
### PoC A: low-privileged namespace user can persist a direct ClusterIssuer Challenge
The following script starts k3s in Docker, installs only the relevant CRDs, creates a platform-owned ClusterIssuer, creates a namespace user with Challenge create permission but no secret or ClusterIssuer read permission, and creates a direct DNS01 Challenge referencing that ClusterIssuer and a cluster resource namespace secret.
The ClusterIssuer is configured to use a legitimate acme-dns host for `victim.example.com`. The direct Challenge uses that same DNS name, but replaces the acme-dns host with an attacker-controlled…
Check your whole app
Dependencies are only half of it. Free and read-only: before you push, run npx shippable-dev scan localhost:3000 in your project folder, no account needed. For your live app, you prove it's yours with a one-line tag first.
References
- github.com/cert-manager/cert-manager/security/advisories/GHSA-8rvj-mm4h-c258
- nvd.nist.gov/vuln/detail/CVE-2026-62290
- github.com/cert-manager/cert-manager/pull/8940
- github.com/cert-manager/cert-manager/pull/8941
- github.com/cert-manager/cert-manager/commit/6bda47297c8fbc6b121b8b76624b668d26f1a155
- github.com/cert-manager/cert-manager/commit/b37dbf01ecea50a0b3a19df0a7fe4c5ad6803f16
- github.com/cert-manager/cert-manager/releases/tag/v1.19.6
- github.com/cert-manager/cert-manager/releases/tag/v1.20.3
- github.com/advisories/GHSA-8rvj-mm4h-c258
Merged from GitHub Advisory Database. Last updated 30 Oct 2026. All vulnerabilities · RSS · JSON