Summary
Kyverno's apiCall feature in ClusterPolicy automatically attaches the admission controller's ServiceAccount token to outgoing HTTP requests. The service URL has no validation — it can point anywhere, including attacker-controlled servers. Since the admission controller's SA has permissions to patch webhook configurations, a stolen token leads to full cluster compromise.
Impact
Two issues combine. First, the service URL flows from the policy spec straight into http.NewRequestWithContext() — no scheme check, no IP restriction, no allowlist. Second, if the request does not already have an Authorization header, Kyverno reads its own SA token from /var/run/secrets/kubernetes.io/serviceaccount/token and injects it as a Bearer token. With the default Helm install, the kyverno-admission-controller SA can read and PATCH MutatingWebhookConfiguration and ValidatingWebhookConfiguration — so a leaked token gives the attacker the ability to bypass or manipulate cluster-wide admission.
Anyone with permission to create or update ClusterPolicy (a relatively common cluster-admin / platform-team grant) can author a policy whose apiCall.service.url points at an attacker-controlled host and harvest the token from the inbound request.
Detection
Audit ClusterPolicy resources for apiCall references whose service.url resolves to an external host or IP. In particular, look for:
- URLs not pointing at in-cluster services (no
.svcsuffix, no internal DNS suffix, public IP) - URLs with explicit IP literals (especially RFC 1918 / link-local) that the admission controller would still resolve
- Recently-created or recently-modified policies authored by an unexpected subject
Cluster operators should also review the audit log for update/patch actions on MutatingWebhookConfiguration / ValidatingWebhookConfiguration performed by the kyverno admission controller's SA outside of expected reconciliation windows.
Mitigation
Upgrade Kyverno to v1.16.4 or later on the 1.16.x line. Users on the 1.17.x branch should track GHSA-qr4g-8hrp-c4rw, which addresses the same class of issue on that line and is patched in 1.18.0.
Workarounds until patched:
- Restrict who can create or update
ClusterPolicyresources via tight RBAC. - Audit and remove existing
ClusterPolicydefinitions that useapiCall.service.urlpointing outside the cluster. - If
apiCallis essential, scope the admission controller's SA more tightly (remove webhook-config patch rights where not strictly required) and rotate the SA token after upgrade.