CVE-2026-22039 Overview
CVE-2026-22039 is a critical authorization boundary bypass in Kyverno, the Kubernetes policy engine used by cloud native platform engineering teams. Versions prior to 1.16.3 and 1.15.3 allow any authenticated user with permission to create a namespaced Policy to issue Kubernetes API requests through the Kyverno admission controller ServiceAccount. The flaw stems from the apiCall feature resolving urlPath without restricting requests to the policy's own namespace. Attackers can read cross-namespace resources such as ConfigMaps and Secrets, and perform cluster-scoped writes including creating ClusterPolicies. Kyverno maintainers shipped fixes in versions 1.16.3 and 1.15.3.
Critical Impact
A low-privileged namespace tenant can escalate to cluster-wide read and write access by abusing the Kyverno admission controller's RBAC, breaking Kubernetes multi-tenancy boundaries.
Affected Products
- Kyverno versions prior to 1.15.3 (1.15.x branch)
- Kyverno versions prior to 1.16.3 (1.16.x branch)
- Kubernetes clusters running namespaced Kyverno Policy resources with apiCall context entries
Discovery Timeline
- 2026-01-27 - CVE-2026-22039 published to NVD
- 2026-02-02 - Last updated in NVD database
Technical Details for CVE-2026-22039
Vulnerability Analysis
Kyverno policies support a context block containing apiCall entries that fetch live cluster data for use in policy logic. When a namespaced Policy (as opposed to a ClusterPolicy) uses an apiCall, the policy author can supply a urlPath value that Kyverno's admission controller resolves against the Kubernetes API server. The vulnerability stems from the absence of a namespace-scope check on the resolved path.
The admission controller executes the request using its own ServiceAccount, which holds broad cluster RBAC permissions required for policy enforcement. Because Kyverno does not constrain the urlPath to the namespace owning the Policy, a tenant who can only create resources in namespace-A can craft a urlPath targeting namespace-B or cluster-scoped endpoints. This maps to [CWE-269] Improper Privilege Management.
Root Cause
The root cause is missing authorization enforcement between the policy's namespace boundary and the admission controller's identity. Kyverno trusts the urlPath field as policy-author input. Context variable substitution further enables attackers to dynamically construct API paths at admission time, expanding the attack surface to any verb and resource the admission controller ServiceAccount can perform.
Attack Vector
An authenticated user with create permission on Policy resources in any namespace authors a malicious Policy whose apiCall.urlPath targets a sensitive resource. When the policy executes, Kyverno performs the request as its admission controller. The attacker reads Secrets from other namespaces or writes a new ClusterPolicy that mutates workloads cluster-wide. Network reachability to the Kubernetes API server is sufficient. No user interaction is required.
No public proof-of-concept code is currently referenced in the advisory. See the GitHub Security Advisory GHSA-8p9x-46gm-qfx2 for technical context.
Detection Methods for CVE-2026-22039
Indicators of Compromise
- Namespaced Policy objects containing context.apiCall.urlPath values referencing namespaces other than the policy's own namespace.
- Kubernetes audit log entries where the Kyverno admission controller ServiceAccount accesses Secrets, ConfigMaps, or cluster-scoped resources outside its expected pattern.
- Unexpected creation of ClusterPolicy resources whose creator metadata traces back to the Kyverno admission controller identity.
- Policy YAML containing context variable substitutions inside urlPath that resolve to /api/v1/namespaces/*/secrets or /apis/kyverno.io/v1/clusterpolicies.
Detection Strategies
- Inventory all Policy resources cluster-wide and inspect every apiCall.urlPath field. Flag any path that does not begin with the policy's owning namespace prefix.
- Enable Kubernetes API server audit logging at the RequestResponse level for the Kyverno admission controller ServiceAccount and alert on cross-namespace reads.
- Use admission control or OPA Gatekeeper rules to reject incoming Policy resources whose urlPath references foreign namespaces or cluster-scoped endpoints.
Monitoring Recommendations
- Track the Kyverno admission controller ServiceAccount for API verb usage anomalies, especially create on clusterpolicies and get/list on secrets.
- Continuously version-check Kyverno deployments to confirm running versions are 1.15.3, 1.16.3, or later.
- Correlate Policy creation events with subsequent admission controller API activity within the same time window.
How to Mitigate CVE-2026-22039
Immediate Actions Required
- Upgrade Kyverno to version 1.16.3 or 1.15.3 immediately on all clusters.
- Audit existing namespaced Policy resources for malicious apiCall.urlPath values before and after upgrade.
- Restrict the create and update verbs on policies.kyverno.io to trusted administrators in multi-tenant clusters.
- Rotate any Secrets that may have been exposed if audit logs show cross-namespace reads by the Kyverno ServiceAccount.
Patch Information
Kyverno maintainers released patches in versions 1.16.3 and 1.15.3. Review the fix commits at GitHub Commit e0ba4de and GitHub Commit eba60fa. Full details are in the GitHub Security Advisory GHSA-8p9x-46gm-qfx2.
Workarounds
- Disable or remove namespaced Policy resources that use apiCall context entries until the upgrade is applied.
- Use Kubernetes RBAC to remove create permission on policies.kyverno.io from non-administrative users and service accounts.
- Reduce the Kyverno admission controller ServiceAccount RBAC to the minimum required, limiting the blast radius of any future bypass.
# Verify the running Kyverno version and upgrade via Helm
kubectl get deployment -n kyverno kyverno-admission-controller \
-o jsonpath='{.spec.template.spec.containers[0].image}'
helm repo update
helm upgrade kyverno kyverno/kyverno -n kyverno --version 3.5.3
# Identify namespaced Policies that use apiCall context entries
kubectl get policy -A -o json | \
jq '.items[] | select(.spec.rules[]?.context[]?.apiCall) | \
{ns:.metadata.namespace, name:.metadata.name}'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

