# Ingress-nginx annotation injection allows retrieval of ingress-nginx serviceaccount token and secrets across all namespaces

Unescaped connection-proxy-header annotation in ingress-nginx nginx.tmpl lets namespace-scoped ingress authors inject nginx directives to read controller files and steal the cross-namespace secret-reading serviceaccount token.

- Payout: hidden
- Severity: high
- Program: Kubernetes
- Found by (vendor credit): Mitch Hulscher
- Found by: amlweems
- Disclosed: 2022-08-13
- CVE: CVE-2021-25742
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/1378175
- Library page: https://bugbountylibrary.com/r/h1%3A1378175
- Tags: area:cloud domain:cloud impact:data-leak impact:internal-access kind:bounty platform:hackerone sev:high tech:kubernetes tech:nginx technique:incomplete-fix technique:source-review vuln:command-injection

**Target:** ingress-nginx controller nginx.tmpl config generation
**Root cause:** Most template variables in nginx.tmpl are not escaped, so the nginx.ingress.kubernetes.io/connection-proxy-header annotation is inserted verbatim into nginx.conf, allowing arbitrary nginx directive injection.
**Steps:**
1. Create/modify an Ingress in an owned namespace with annotation `nginx.ingress.kubernetes.io/connection-proxy-header` containing injected nginx directives (e.g. a `proxy_set_header`/`include`-style payload) to read files.
2. Apply the Ingress against ingress-nginx v1.0.4; controller renders nginx.tmpl into nginx.conf with the unescaped annotation.
3. Trigger the affected location so injected directives execute and exfiltrate the target file contents.
4. Read `/var/run/secrets/kubernetes.io/serviceaccount/token` and use it to list secrets across all namespaces.
**How found:** While exploring CVE-2021-25742, noticed most template variables in nginx.tmpl are not escaped; tested the connection-proxy-header annotation which is inserted directly into nginx.conf, confirming a variant injection.
**Exploitation:** Attacker with ingress create/modify rights in one namespace injects nginx directives via the connection-proxy-header annotation; the controller renders them into nginx.conf, enabling arbitrary file read on the controller pod including the mounted serviceaccount token, which has cluster-wide secret read permission.
**Escalation:** Namespace-scoped ingress write escalates to cluster-wide secret read via the controller's over-privileged serviceaccount token.
**Insight:** When a template engine escapes some fields, enumerate every annotation/variable that reaches the rendered config and test each individually — partial escaping means sibling fields remain injectable.
