# Proxy normalization, cache isolation, and request boundaries

Investigate layered HTTP behavior with isolated cache keys and controlled front-end/back-end traffic.

## Investigation sequence

1. Map HTTP processing layers
2. Prove isolation
3. Establish normal cache behavior
4. Change one interpretation input
5. Verify second controlled client
6. Purge and document

## Used in these playbooks

[Web & API](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/web-api.html) · [OSS & self-hosted](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/oss.html) · [Cloud & containers](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/cloud.html) · [Network services](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/network.html)

### Setup and invariant

Use a local proxy plus application, or a program-provided isolated cache namespace and upstream pool. Record protocol on each hop, request normalization, cache key, cache policy, authentication placement, and whether connections are reused. The invariant is: **all layers agree on the request target, request boundary, and which client may receive a cached representation**. These tests can affect requests other than your own; an unproven random query parameter is not isolation.

### Numbered test procedure

1. **Map the layers.** From configuration or operator-provided logs, identify browser → CDN/proxy → application. Capture an ordinary controlled URL from two independent clients. Record `Age`, cache-status headers where present, `Vary`, `Cache-Control`, effective host/path, and origin logs. A header name or latency difference alone does not establish caching.
2. **Prove the test namespace.** Configure a dedicated local path or verified cache-key component. Request two distinct canary paths and confirm they remain separate through origin and cache logs. A query string may be ignored, normalized, or partially keyed. If separation cannot be established in a shared environment, keep mutation experiments in the replica.
3. **Test cache poisoning.** On a fresh isolated key, vary one input that changes origin output but may not be in the cache key, such as an observed forwarding header used in a generated absolute link. Use a harmless marker host under your control. Make a second request without that input and inspect whether the marker persists. Confirm a control key remains clean. The evidence must show an altered representation served from shared cache to the second controlled client. [Cache poisoning](https://portswigger.net/web-security/web-cache-poisoning).
4. **Test cache deception.** Create a private page containing A's unique synthetic marker. In the lab, compare the canonical path with one suffix/path-normalization variant that the origin resolves to the same page but the cache may treat as static. Request that variant as A, then as anonymous B. Verify B receives A's marker because of caching; compare B's direct origin response or a fresh key. Sharing via an intentionally public capability URL is not deception. [Cache deception](https://portswigger.net/web-security/web-cache-deception).
5. **Test parsing agreement in isolation.** Capture the bytes seen by front end and backend for a normal request. In the lab, create one malformed framing case and observe whether both components reject it consistently. For ambiguous length/framing, verify how many requests each layer parsed and where the second controlled request begins. Do not treat a timeout as proof, or use unrelated users' responses to demonstrate desynchronization. HTTP/1.1 framing and HTTP/2-to-HTTP/1 translation must be assessed separately. [HTTP/1.1 framing](https://www.rfc-editor.org/rfc/rfc9112.html), [Request smuggling](https://portswigger.net/web-security/request-smuggling).
6. **Verify consequence and clean up.** Save origin/cache logs, exact requests, normalized targets, cache keys, and client identities. Purge only the dedicated test namespace or restart the disposable cache. Report whether the outcome is poisoned content, private response disclosure, authorization normalization bypass, or request-boundary disagreement; those are distinct findings.

### Command card

These ordinary requests establish a local cache baseline. Configure `/bb-cache/case-01` and `/bb-cache/case-02` as separate keys in your own proxy first. A later poisoning probe must vary only a specific source-identified input.

```bash
mkdir -p evidence/cache
curl -q --noproxy '*' --max-time 10 -D evidence/cache/first.h \
  -o evidence/cache/first.txt http://127.0.0.1:8080/bb-cache/case-01
curl -q --noproxy '*' --max-time 10 -D evidence/cache/second.h \
  -o evidence/cache/second.txt http://127.0.0.1:8080/bb-cache/case-01
curl -q --noproxy '*' --max-time 10 -D evidence/cache/control.h \
  -o evidence/cache/control.txt http://127.0.0.1:8080/bb-cache/case-02
```

### Report threshold and checklist

Report a controlled second-client effect or demonstrated parser disagreement with a meaningful security boundary. Mere caching, unexpected 400/502 responses, reflected Host values, and differences caused by the testing proxy are common false positives.

- [ ] Cache namespace and upstream isolation verified.
- [ ] Every HTTP hop and protocol recorded.
- [ ] Normal, mutated, second-client, and clean-key controls saved.
- [ ] No production response-queue capture or broad desync probing.
- [ ] Test cache entries purged after evidence collection.

Local curl examples bypass environment proxies with `--noproxy '*'`; `-q` alone only suppresses curl configuration files. These snippets target loopback and do not follow redirects. [curl manual](https://curl.se/docs/manpage.html).


### Cache semantics and revocation control

Interpret response directives precisely: unqualified `no-cache` permits storage but requires validation before reuse; `no-store` prohibits storage/reuse subject to the specification's defined exceptions; unqualified `private` prevents shared-cache storage but permits private-cache storage. `Set-Cookie` alone does not disable caching. Requests containing `Authorization` have special shared-cache restrictions, with explicit exceptions such as `public` and `s-maxage`; cookie-authenticated requests need their own correct response policy and cache partitioning. Read the effective configuration and observe behavior. [RFC 9111, sections 3.5, 5.2 and 7.3](https://www.rfc-editor.org/rfc/rfc9111.html).

In an isolated namespace, compare A, anonymous B, and a fresh control key after A changes or deletes the private marker. Also exercise one normal conditional request if the application uses validators. Inspect which identity the origin checked and which stored body the cache reused after a `304`. Do not infer privacy from an `Age: 0`, absent cache header, or an initial miss. Report stale post-revocation access against the product's promised lifecycle, distinguishing a previously downloaded copy from a newly served shared response.

- [ ] Storage, revalidation and private/shared-cache behavior distinguished.
- [ ] Fresh, cached and post-change responses compared where applicable.


## Vulnerability reverse references

- [Web cache poisoning](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/vulnerabilities/web-cache-poisoning-unkeyed-input.html) — Unkeyed attacker-controlled input changes a representation later served from shared cache.
- [Web cache deception](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/vulnerabilities/web-cache-deception-private-response.html) — A path/cache-policy discrepancy stores a private response for retrieval by another client.
- [HTTP request smuggling / desynchronization](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/vulnerabilities/http-request-boundary-desynchronization.html) — Two HTTP-processing components disagree about request boundaries or parsing.
- [Untrusted Host or forwarding-header origin construction](https://bug-bounty-field-manual.kmahshooq.chatgpt.site/vulnerabilities/host-header-origin-trust.html) — The application constructs a security-sensitive origin from request metadata that an attacker can influence.
