Security
HTTP Proxy Framing: Make Every Hop Agree on Request Boundaries
Review HTTP request boundaries across proxies and origins with strict framing policy, harmless test cases and connection-level checks in authorized staging.
In this article
An HTTP proxy and its origin must agree on where one request ends and the next begins. If they interpret framing differently, bytes intended as one message can be treated as part of another. Defensive review should focus on consistent boundaries, strict rejection policy, and connection handling across the complete deployed path.
RFC 9112 defines HTTP/1.1 message framing, including the relationship between Content-Length and Transfer-Encoding. This guide describes an authorized defensive review. It does not provide request-smuggling payloads or instructions for probing unrelated services.
Inventory the real chain
List every component handling an inbound request: edge service, load balancer, reverse proxy, service mesh, application server, and framework. Record software versions and the protocol used on each connection.
A browser’s HTTP/2 connection does not mean every downstream hop uses HTTP/2. Translation to HTTP/1.1 can introduce a framing boundary that still needs review. Likewise, a development environment with one server does not represent production with several intermediaries.
Identify who owns patching and configuration at each hop. If a managed edge abstracts part of the chain, use its current official guidance and supported settings rather than assuming undocumented internals.
Write a clear acceptance policy
For normal requests, define supported framing and maximum body size. For malformed or ambiguous input, prefer a documented strict rejection policy consistent across the chain. Do not let one component silently “repair” a message in a way the next component interprets differently.
RFC 9112 states that senders must not combine Content-Length with Transfer-Encoding. Its receiving and forwarding rules address how such messages are handled. Review those rules with your implementation documentation rather than inventing a homegrown parser from a few header examples.
Avoid ad hoc string filters as the primary defense. Case handling, whitespace, duplicate fields, protocol conversion, and connection reuse make this a parser-consistency problem, not just a search for one suspicious text pattern.
Observe boundaries without collecting secrets
In staging, assign each harmless test request a unique identifier and use a small synthetic body. Record which identifier, path, body length, and completion status the origin observes. Exclude authentication tokens and real customer payloads.
Compare ingress and origin records for a short controlled sequence. A successful response is not enough if the origin received a different body length or associated the next request with the wrong connection state.
Include requests sent on fresh connections and reused connections. Boundary problems can become visible only when another request follows the first. Keep tests inside isolated infrastructure so an unexpected interpretation cannot affect another user.
Build a non-weaponized regression matrix
Start with valid cases: a request without a body, a fixed-length small body, and a supported streamed body. Verify that each arrives intact and that the following request remains separate.
Then use your vendor’s supported conformance or security test suite for invalid framing. Configure the expected result as rejection and safe connection closure where required. Do not copy exploit traffic from an untrusted post into a shared production connection pool.
Test body-size limits on both sides of each proxy boundary. If one hop accepts a body that another cannot process, verify that failure is explicit and that no unread bytes remain available to be confused with a later request.
Review normalization and forwarding
For accepted traffic, confirm how the proxy constructs the outbound message. It should not forward contradictory framing metadata after decoding or transforming a body. Compression changes, buffering, and protocol downgrades all deserve explicit documentation.
Check whether framework middleware reads raw headers differently from the server’s parser. A security check that trusts one representation while request dispatch uses another can undermine otherwise strict edge behavior.
Where the product provides a supported strict mode, test it against legitimate clients before broad rollout. Rejection logs should make compatibility problems diagnosable without exposing bodies. A temporary compatibility exception should have a narrow scope and an expiry owner.
Patch and retest the deployed combination
Update affected components according to official advisories and your change process. Patching one proxy does not prove the entire chain is aligned if another parser remains old or an origin is reachable through a separate path.
Verify that intended origins cannot be reached through an undocumented bypass that misses the edge’s checks. This is an access-boundary review, not authorization to scan systems outside your ownership.
After changes, rerun the same harmless valid cases and supported rejection suite. Preserve versions, configuration hashes, and observed results so a later proxy upgrade can be compared with a known baseline.
Include an explicit rollback test for the proxy configuration. If legitimate clients fail after strict-mode rollout, restore the reviewed configuration while investigating; do not leave an undocumented parser exception enabled permanently.
Conclusion
Request framing is a shared contract across every hop. Inventory translations, enforce strict supported behavior, inspect origin boundaries, and test connection reuse in staging rather than relying on one edge response or a text-based filter.