# Proxy upgrade and trailer smuggling

Sanitizers that scan only headers, and Upgrade tokens forwarded without an allowlist

_Area: Web infrastructure and server-side requests. Seen in 3 disclosed reports; latest 2026-09-10. Updated 2026-10-24._

## How it works
A reverse proxy sanitizes or routes based on `req.Header`, but the same names can arrive through a second channel the sanitizer never inspects: declared HTTP trailers, or a client-supplied `Upgrade` token. The assumption that "all client-controlled metadata lives in the header map" breaks. In Go, the server pre-fills declared trailer keys before handlers run, so a sanitizer looping over `req.Header` misses them [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-v67p-phpq-fc8x.md). Separately, a proxy that forwards arbitrary `Connection: Upgrade`/`Upgrade` tokens without an allowlist will, on a backend `101 Switching Protocols`, enter raw tunnel mode and stop applying routing and middleware [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w4v4-9rw7-5326.md).

## Where it shows up
- Sanitization/delete handlers (alias, underscore, X-Forwarded-*) that iterate `req.Header` only, while doc comments claim to cover trailers [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-v67p-phpq-fc8x.md).
- Body-buffering or retry middleware that merges trailers into headers before forwarding [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-v67p-phpq-fc8x.md).
- `removeConnectionHeaders` logic that preserves `Upgrade` whenever `Connection: Upgrade` is present, with no token validation [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w4v4-9rw7-5326.md).
- WebSocket-upgrade checks used as the only gate instead of an explicit allowlist [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w4v4-9rw7-5326.md).
- Load balancers/CDNs that honor non-compliant `h2c` upgrades and stop per-request processing after upgrade [E2](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-h2c-smuggling-in-the-wild.md).

## How to review
For every sanitizer, confirm the invariant: the set of client-controlled names it rejects or strips is identical across headers and trailers, and trailer keys are enumerated and filtered before any merge. Check that the code reads `req.Trailer` explicitly, not just `req.Header`. For upgrades, confirm the invariant: only an explicit allowlist of upgrade tokens (e.g. `websocket`) is forwarded; any other token is stripped or rejected, and a `101` cannot bypass routers or auth middleware. Trace the proxy path end to end: what happens to the connection after `101`?

## Variants seen
- Trailer-based sanitizer bypass reaching trailer-merging backends [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-v67p-phpq-fc8x.md).
- Client-supplied `h2c` upgrade forwarded to backend, `101` yields raw tunnel skipping BasicAuth [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w4v4-9rw7-5326.md).
- H2C smuggling through cloud load balancers to reach restricted paths and evade WAF [E2](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-h2c-smuggling-in-the-wild.md).

## Impact and severity
High: authentication and WAF bypass, access to restricted paths, and header-injection reach into backends [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-v67p-phpq-fc8x.md)[E2](https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-h2c-smuggling-in-the-wild.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-w4v4-9rw7-5326.md). Severity rises when the proxy is the sole auth boundary and when backends merge trailers or trust forwarded headers.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-v67p-phpq-fc8x.md
- E2: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-h2c-smuggling-in-the-wild.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-w4v4-9rw7-5326.md
