On the current NVD feed, CVE-2026-122310 landed with a CVSS 9.9 (Critical) — and after reading the technical details, the score is justified. This is not a memory corruption bug in a corner-case component. It is a logic flaw in Kyverno, one of the most widely deployed policy engines in the Kubernetes ecosystem, and it collapses the entire RBAC boundary between a namespace-scoped user and cluster administrator.
Affected versions: Kyverno 1.19.1 through all releases before 1.19.2. The flaw lives in how Kyverno validates the context.apiCall urlPath field in a Policy. Kyverno cleans the path (resolving ../ segments) before validating it — but then executes the raw, uncleaned path against the Kubernetes API. The Kubernetes client discards URL fragments (#) and query strings (?), which means an attacker can hide traversal segments behind them. The result: a user with nothing more than permission to create a Policy in their own namespace can smuggle ../ sequences into an API call and reach cluster-scoped endpoints using Kyverno's own ServiceAccount — which in most real-world deployments holds powerful, often cluster-admin-equivalent, RBAC.
If you run multi-tenant clusters, developer self-service namespaces, CI/CD service accounts, or any environment where non-administrators can author admission policies, treat this as a priority-one remediation. The exploitation requirement is trivial: kubectl create rights on policies in one namespace. No host access, no container escape, no exotic primitives — just a crafted YAML.
Technical Analysis
Affected Products and Versions
| Component | Affected Versions | Fixed Version |
|---|---|---|
| Kyverno (policy engine for Kubernetes) | 1.19.1 up to (but not including) 1.19.2 | 1.19.2 |
All Kubernetes platforms (EKS, AKS, GKE, OpenShift, self-managed) running a vulnerable Kyverno build are exposed. The vulnerability is remotely exploitable over the network via the Kubernetes API — which is exactly why NVD scored it 9.9.
How the Vulnerability Works — Defender's View
The attack chain breaks down as follows:
- Attacker prerequisite: A Kubernetes identity (user or ServiceAccount) with RBAC permission to create
Policyresources (policies.kyverno.io) in at least one namespace. This is commonly granted to developers, GitOps operators, or tenant teams in self-service models. - Crafted Policy: The attacker authors a Policy that uses a
context.apiCallblock. TheurlPathis constructed so that traversal segments (../) are concealed behind a fragment (#) or query (?) delimiter. - Validation bypass: Kyverno's admission logic cleans the path — resolving and normalizing the traversal — and validates the cleaned result. The cleaned path looks benign and passes whatever allowlist checks exist.
- Raw path execution: Kyverno then issues the API call using the original raw path. The Kubernetes Go client strips everything after
#or?, but the traversal segments positioned before those delimiters are resolved by the API request path handling — allowing the request to escape the intended namespace scope. - Privilege pivot: The request executes under the Kyverno admission controller's ServiceAccount identity, not the attacker's. In default and many production Helm-chart configurations, that ServiceAccount is bound to highly permissive ClusterRoles — frequently enough to read all Secrets, bind ClusterRoles, or create privileged workloads.
- Cluster admin: From there, classic Kubernetes escalation paths apply: read
clusterrolebinding/secretobjects cluster-wide, mint a token for an existing cluster-admin ServiceAccount, or create a new ClusterRoleBinding granting the attackercluster-admin.
This is a textbook confused deputy vulnerability: Kyverno's elevated identity is tricked into performing actions the low-privilege caller could never perform directly. It follows the same pattern we've seen repeatedly in admission-controller and policy-engine privilege escalations disclosed across 2025–2026 — the policy engine's ServiceAccount is the crown jewel, and any input path it trusts must be treated as hostile.
Exploitation Status
As of publication, CVE-2026-122310 is documented in NVD with full technical detail sufficient to reconstruct the exploit primitive. A public proof-of-concept has not been confirmed, and the CVE is not yet listed in CISA's Known Exploited Vulnerabilities catalog — but the barrier to weaponization is effectively zero. Any Kubernetes operator who reads the NVD description can build the malicious Policy in an afternoon. Assume exploitation attempts will follow quickly, and assume sophisticated actors already have it. Do not wait for a KEV listing to patch.
Detection & Response
Detection for this vulnerability centers on two observables: (1) Policy objects containing suspicious urlPath values (fragments, query strings, or traversal sequences in context.apiCall), and (2) anomalous API activity from the Kyverno ServiceAccount — especially requests touching cluster-scoped resources it has no routine reason to access, or requests whose paths show normalization artifacts.
Your primary telemetry source is the Kubernetes API server audit log. If you are not shipping audit logs to your SIEM today, this CVE is your forcing function. Ensure your audit policy logs RequestResponse level for policies.kyverno.io and at least Metadata (ideally Request) for all requests by the Kyverno admission controller ServiceAccount (system:serviceaccount:kyverno:kyverno-admission-controller or your deployment's equivalent).
Sigma Rules
---
title: Kyverno Policy Created With Suspicious apiCall URL Path Traversal
description: Detects creation or modification of Kyverno Policy resources whose context.apiCall urlPath contains fragments, query strings, or directory traversal sequences — the exploitation signature of CVE-2026-122310. Source telemetry is the Kubernetes API server audit log.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-122310
author: Security Arsenal
date: 2026/04/06
status: experimental
logsource:
product: kubernetes
service: audit
detection:
selection_verb:
verb:
- 'create'
- 'update'
- 'patch'
selection_resource:
objectRef.resource:
- 'policies'
- 'clusterpolicies'
selection_path:
requestObject|contains:
- 'urlPath'
selection_suspicious:
requestObject|contains:
- '..'
- '#'
- '?'
condition: selection_verb and selection_resource and selection_path and selection_suspicious
falsepositives:
- Legitimate apiCall usage with query parameters — review the specific urlPath value; traversal sequences (../) have no legitimate use and should always alert
level: high
---
title: Kyverno ServiceAccount Accessing Cluster-Scoped Resources Anomalously
description: Detects the Kyverno admission controller ServiceAccount performing write operations or reading Secrets at cluster scope — consistent with post-exploitation behavior of CVE-2026-122310 where attacker-controlled apiCall requests execute under Kyverno's identity.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-122310
- https://attack.mitre.org/techniques/T1078/
author: Security Arsenal
date: 2026/04/06
status: experimental
logsource:
product: kubernetes
service: audit
detection:
selection_user:
user.username|startswith: 'system:serviceaccount:kyverno'
selection_verb:
verb:
- 'create'
- 'update'
- 'patch'
- 'delete'
selection_cluster_scope:
objectRef.resource:
- 'clusterrolebindings'
- 'clusterroles'
- 'secrets'
- 'serviceaccounts'
filter_namespace_scoped_secret_reads:
verb: 'get'
condition: selection_user and selection_verb and selection_cluster_scope and not filter_namespace_scoped_secret_reads
falsepositives:
- Kyverno cleanup or background controller operations — baseline normal controller behavior per cluster and alert on deviations; writes to clusterrolebindings/clusterroles by Kyverno's identity should be near-zero in steady state
level: high
---
title: Kubernetes API Request Path Containing Traversal With Fragment or Query Delimiter
description: Detects raw request URIs in the Kubernetes audit log that combine directory traversal sequences with fragment (#) or query (?) delimiters — the raw-path execution artifact of CVE-2026-122310 that the Kubernetes client strips before dispatch.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-122310
author: Security Arsenal
date: 2026/04/06
status: experimental
logsource:
product: kubernetes
service: audit
detection:
selection:
requestURI|contains:
- '../'
- '..%2f'
- '..%252f'
- '%2e%2e'
condition: selection
falsepositives:
- Extremely rare in legitimate Kubernetes API traffic; encoded traversal in any requestURI should be investigated immediately
level: critical
KQL (Microsoft Sentinel)
The following hunts assume Kubernetes audit logs are ingested into Sentinel — either via the CommonSecurityLog/Syslog pipeline from a control-plane log forwarder, or via a diagnostic/log-analytics pipeline (e.g., AKS control plane logs landed in a custom KubeAudit_CL or ContainerLog-style table). Adjust table and field names to your ingestion schema.
// Hunt 1: Kyverno Policy objects with traversal/fragment/query in apiCall urlPath
// Covers the exploitation primitive for CVE-2026-122310
let Lookback = 14d;
union isfuzzy=true
(CommonSecurityLog
| where TimeGenerated > ago(Lookback)
| where AdditionalExtensions has "policies" and AdditionalExtensions has "urlPath"
| extend RawLog = tostring(AdditionalExtensions)),
(Syslog
| where TimeGenerated > ago(Lookback)
| where SyslogMessage has "kyverno.io" and SyslogMessage has "urlPath"
| extend RawLog = SyslogMessage)
| where RawLog has_any ("../", "..%2f", "%2e%2e")
or (RawLog has "urlPath" and RawLog has_any ("#", "?"))
| project TimeGenerated, Computer, SourceIP, RawLog
| order by TimeGenerated desc;
// Hunt 2: Kyverno ServiceAccount performing writes to cluster-scoped RBAC or Secrets
// Post-exploitation indicator: confused-deputy API calls under Kyverno's identity
let Lookback = 14d;
Syslog
| where TimeGenerated > ago(Lookback)
| where SyslogMessage has "system:serviceaccount:kyverno"
| where SyslogMessage has_any ("clusterrolebindings", "clusterroles", "\"/secrets\"")
| where SyslogMessage has_any ("\":\"create\"", "\":\"update\"", "\":\"patch\"", "\":\"delete\"")
| extend AuditEvent = parse_json(SyslogMessage)
| project TimeGenerated,
Verb = tostring(AuditEvent.verb),
User = tostring(AuditEvent.user.username),
Resource = tostring(AuditEvent.objectRef.resource),
Namespace = tostring(AuditEvent.objectRef.namespace),
RequestURI = tostring(AuditEvent.requestURI),
SourceIP = tostring(AuditEvent.sourceIPs)
| order by TimeGenerated desc;
Velociraptor VQL
For DFIR validation on Kubernetes control-plane nodes, hunt the on-disk API server audit log directly. This is valuable when SIEM ingestion lags, when you need pre-ingestion historical depth, or when verifying whether exploitation occurred before the patch window.
-- Hunt kube-apiserver audit logs on control-plane nodes for CVE-2026-122310 indicators:
-- Policy objects carrying traversal/fragment/query urlPaths, and raw requestURIs with traversal
LET audit_logs = glob(globs='/var/log/kubernetes/audit*.log')
, '/var/log/kube-apiserver/audit*.log'
, '/var/log/kubernetes/apiserver/audit*.log')
SELECT FullPath AS AuditLogFile,
Line,
parse_json(data=Line).verb AS Verb,
parse_json(data=Line).user.username AS Username,
parse_json(data=Line).objectRef.resource AS Resource,
parse_json(data=Line).requestURI AS RequestURI,
parse_json(data=Line).sourceIPs AS SourceIPs
FROM foreach(row=audit_logs,
query={
SELECT Line
FROM parse_lines(filename=FullPath)
WHERE (Line =~ 'urlPath' AND Line =~ '(\\.\\./|%2e%2e|#|\\?)' AND Line =~ 'kyverno.io')
OR (Line =~ 'requestURI' AND Line =~ '(\\.\\./|\\.\\.%2f|%2e%2e)')
})
Remediation and Audit Script
Run the following from a workstation with cluster-admin kubectl access and Helm. It verifies your Kyverno version, audits every existing Policy/ClusterPolicy for the exploitation signature (this is the critical step — a malicious Policy created before patching remains live after the upgrade), snapshots the Kyverno ServiceAccount's RBAC bindings for review, and performs the upgrade.
#!/usr/bin/env bash
# CVE-2026-122310 — Kyverno verify / audit / upgrade script
set -euo pipefail
echo "=== [1] Current Kyverno version ==="
kubectl -n kyverno get deploy -l app.kubernetes.io/name=kyverno \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.template.spec.containers[*].image}{"\n"}{end}' || true
KYVERNO_IMG=$(kubectl -n kyverno get deploy kyverno-admission-controller \
-o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null || echo "NOT_FOUND")
echo "Admission controller image: ${KYVERNO_IMG}"
if echo "${KYVERNO_IMG}" | grep -Eq 'v?1\.19\.(0|1)([^0-9]|$)'; then
echo "[!!] VULNERABLE version detected (1.19.1 or earlier in the 1.19 line). Upgrade required."
else
echo "[OK] Version does not match vulnerable range — confirm it is >= v1.19.2."
fi
echo
echo "=== [2] Audit all Policies/ClusterPolicies for malicious apiCall urlPath ==="
echo "Looking for urlPath values containing ../, #, or ? (CVE-2026-122310 signature)"
for kind in policies clusterpolicies; do
kubectl get "${kind}.kyverno.io" -A -o json 2>/dev/null | \
jq -r '.items[] | select(tostring | test("urlPath")) |
select(tostring | test("\\.\\./|\\.\\.%2[fF]|%2[eE]%2[eE]")) |
"SUSPECT: \(.kind) \(.metadata.namespace // "cluster")/\(.metadata.name)"' || true
# Any urlPath containing a fragment or query delimiter also warrants review
kubectl get "${kind}.kyverno.io" -A -o json 2>/dev/null | \
jq -r '.items[] | . as $p |
($p | tostring | [scan("urlPath[^,}]*")])[]? |
select(test("#|\\?")) |
"REVIEW (fragment/query in urlPath): \($p.metadata.namespace // "cluster")/\($p.metadata.name)"' || true
done
echo
echo "=== [3] Snapshot Kyverno ServiceAccount RBAC bindings (review for over-privilege) ==="
kubectl get clusterrolebindings -o json | \
jq -r '.items[] | select(.subjects[]? | .kind=="ServiceAccount" and .namespace=="kyverno") |
"\(.metadata.name) -> \(.roleRef.name)"'
echo
echo "=== [4] Upgrade Kyverno to >= 1.19.2 via Helm ==="
helm repo add kyverno https://kyverno.github.io/kyverno/ 2>/dev/null || true
helm repo update kyverno
helm upgrade kyverno kyverno/kyverno -n kyverno --version '>=1.19.2' --reuse-values
echo
echo "=== [5] Post-upgrade verification ==="
kubectl -n kyverno rollout status deploy/kyverno-admission-controller --timeout=180s
kubectl -n kyverno get deploy kyverno-admission-controller \
-o jsonpath='{.spec.template.spec.containers[0].image}'
echo
echo "DONE. Re-run step [2] after upgrade and delete/quarantine any flagged policies."
Remediation
1. Upgrade immediately to Kyverno 1.19.2 or later. This is the only complete fix — the patched release validates the actual executed path, closing the validate-clean/execute-raw discrepancy. Pull the patched chart/image from the official Kyverno release channels and confirm the running admission controller image tag post-upgrade.
2. Audit all existing Policy and ClusterPolicy objects before and after patching. Patching stops new exploits; it does not remove a malicious Policy already created. Any context.apiCall urlPath containing ../, #, or ? is suspect — traversal sequences have no legitimate purpose in this field. Delete or quarantine flagged policies and investigate their creators.
3. Review who can create policies. CVE-2026-122310's entire exploitation prerequisite is create on policies.kyverno.io. Inventory every Role/ClusterRole granting verbs on Kyverno policy resources. In most organizations, policy authoring should be restricted to platform/security teams via GitOps — not delegated to tenant namespaces. Tighten this now, independent of the patch.
4. Reduce the blast radius of the Kyverno ServiceAccount. The confused-deputy impact scales with Kyverno's privileges. Audit the ClusterRoles bound to Kyverno's ServiceAccounts. Remove cluster-admin equivalents where feasible; scope Secret read access; separate the admission controller's identity from controllers that need broader rights. If Kyverno cannot bind clusterroles or read all secrets, a future confused-deputy bug in the same class yields far less.
5. Verify audit logging coverage. Confirm your API server audit policy captures RequestResponse for Kyverno policy resources and at least Metadata+request URI for Kyverno ServiceAccount activity — and that those logs reach your SIEM with usable retention. You cannot retro-hunt what you never logged.
6. Post-patch IR sweep. If you ran a vulnerable version in any multi-tenant or internet-reachable cluster, treat the window between 1.19.1 deployment and patch as an exposure period. Review audit logs for the indicators above: suspicious urlPath values, Kyverno-identity writes to RBAC objects, new ClusterRoleBindings, and newly created cluster-admin-bound ServiceAccount tokens. Any hit warrants a full credential-rotation and persistence sweep of the cluster.
References: NVD — CVE-2026-122310 and the official Kyverno security advisory/release notes for v1.19.2. Monitor the CISA KEV catalog — given the CVSS 9.9 score and trivial exploitation requirements, addition is plausible if in-the-wild activity is confirmed.
Bottom Line
CVE-2026-122310 is a reminder that in Kubernetes, the admission layer is part of your attack surface — and its ServiceAccount is part of your crown jewels. A single RBAC grant on policy resources, combined with a validate-one-path/execute-another logic bug, is all it takes to hand over the cluster. Patch to 1.19.2 today, audit your policies and bindings this week, and permanently restrict who can author Kyverno policies. The patch takes an hour; the IR engagement takes a quarter.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.