Skip to content

fix(proxy): recompute Content-Length when repeat_request replaces the body#604

Open
Osamaali313 wants to merge 2 commits into
usestrix:mainfrom
Osamaali313:fix/proxy-content-length-on-body-replace
Open

fix(proxy): recompute Content-Length when repeat_request replaces the body#604
Osamaali313 wants to merge 2 commits into
usestrix:mainfrom
Osamaali313:fix/proxy-content-length-on-body-replace

Conversation

@Osamaali313

Copy link
Copy Markdown

Fixes #603

Problem

build_raw_request (strix/tools/proxy/caido_api.py) only auto-computes Content-Length when it is absent. So when repeat_request replaces the body (modifications={"body": ...}), the original request's stale Content-Length is carried over and sent — a server reading exactly that many bytes truncates the new body (or stalls), silently dropping the modified/injected payload. That defeats parameter-tampering / injection replays (the core use of the tool) and yields misleading negative results.

Reproduction

Original body "old" (Content-Length: 3); replacing it with a 37-byte body still sends Content-Length: 3.

Fix

In apply_modifications, when the body is replaced, drop any carried-over Content-Length (case-insensitively) so build_raw_request recomputes it — unless the caller explicitly set Content-Length in the same call's header modifications (preserves deliberate length-mismatch / smuggling tests).

Tests

Adds tests/test_proxy_caido_api.py: body replacement recomputes Content-Length; explicit override preserved; no-body modification leaves it untouched. Verified RED→GREEN on the real functions (3 passed).

… body

build_raw_request only sets Content-Length when absent, so a repeat_request that replaces the body kept the original request's stale Content-Length and sent a wrong body length — truncating the modified/injected payload (which defeats parameter-tampering and injection replays). apply_modifications now drops a carried-over Content-Length (case-insensitively) on body replacement so it is recomputed, unless the caller explicitly set Content-Length in the same call. Adds tests.
Copilot AI review requested due to automatic review settings June 29, 2026 19:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug in apply_modifications where replacing the request body via repeat_request would leave behind the original request's stale Content-Length header, causing build_raw_request to silently forward the wrong length to the target server. The fix drops any carried-over Content-Length (case-insensitively) when the body is replaced, unless the caller explicitly sets Content-Length in the same modification call, and adds a new test file to verify the behavior.

  • Core fix (caido_api.py): apply_modifications now strips stale Content-Length entries on body replacement; the existing build_raw_request recompute path handles filling in the correct value automatically.
  • Explicit-override preservation: If the caller passes modifications={\"body\": ..., \"headers\": {\"Content-Length\": \"...\"}}, the explicit value is kept intact — enabling deliberate length-mismatch / request-smuggling tests.
  • Tests (tests/test_proxy_caido_api.py): Three new tests cover the recompute path, the explicit-override path, and the no-body-modification path; the empty-body replacement case (body=\"\") is not yet covered and exposes a pre-existing gap in build_raw_request's if body guard.

Confidence Score: 4/5

Safe to merge for the common case; the fix correctly handles non-empty body replacement and explicit Content-Length overrides.

The fix is logically sound and the three new tests pass for the scenarios described in the PR. The only gap is the empty-body replacement path: build_raw_request skips adding Content-Length when the body string is falsy, so replacing a body with an empty string produces a raw POST with no Content-Length header at all. This is a narrow edge case and the behavior is no worse than before the PR, but it is an unverified code path.

strix/tools/proxy/caido_api.py line 160 and the corresponding test file would benefit from a follow-up to handle the empty-body replacement case.

Important Files Changed

Filename Overview
strix/tools/proxy/caido_api.py Adds stale Content-Length removal in apply_modifications when body is replaced; logic is correct for the non-empty body case but an empty-body replacement leaves the raw request with no Content-Length header
tests/test_proxy_caido_api.py New test file covering body-replacement recompute, explicit-override preservation, and no-body-mod leave-untouched; missing a case for empty-string body replacement
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
tests/test_proxy_caido_api.py:14-28
**Missing test: empty-body replacement leaves no `Content-Length`**

The test suite covers the happy path (non-empty replacement) and the explicit-override path, but not the case where `modifications={"body": ""}`. `apply_modifications` will correctly drop the old `Content-Length`, but `build_raw_request` guards its recomputation with `if body and ...` (line 160 of `caido_api.py`), so an empty string is falsy and the header is never added back. The resulting raw POST request contains no `Content-Length` header at all — some servers will reject it or behave unexpectedly. A test and a fix in `build_raw_request` (changing the condition to `if body is not None and ...`) would close this gap.

Reviews (1): Last reviewed commit: "fix(proxy): recompute Content-Length whe..." | Re-trigger Greptile

Comment on lines +14 to +28

def test_body_replacement_recomputes_content_length() -> None:
components = {
"method": "POST",
"headers": {"Host": "x.test", "Content-Length": "3"},
"body": "old",
}
new_body = "this is the new and much longer body!"
result = apply_modifications(components, {"body": new_body}, "http://x.test/submit")
_conn, raw = build_raw_request(
method=result["method"],
url=result["url"],
headers=result["headers"],
body=result["body"],
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing test: empty-body replacement leaves no Content-Length

The test suite covers the happy path (non-empty replacement) and the explicit-override path, but not the case where modifications={"body": ""}. apply_modifications will correctly drop the old Content-Length, but build_raw_request guards its recomputation with if body and ... (line 160 of caido_api.py), so an empty string is falsy and the header is never added back. The resulting raw POST request contains no Content-Length header at all — some servers will reject it or behave unexpectedly. A test and a fix in build_raw_request (changing the condition to if body is not None and ...) would close this gap.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/test_proxy_caido_api.py
Line: 14-28

Comment:
**Missing test: empty-body replacement leaves no `Content-Length`**

The test suite covers the happy path (non-empty replacement) and the explicit-override path, but not the case where `modifications={"body": ""}`. `apply_modifications` will correctly drop the old `Content-Length`, but `build_raw_request` guards its recomputation with `if body and ...` (line 160 of `caido_api.py`), so an empty string is falsy and the header is never added back. The resulting raw POST request contains no `Content-Length` header at all — some servers will reject it or behave unexpectedly. A test and a fix in `build_raw_request` (changing the condition to `if body is not None and ...`) would close this gap.

How can I resolve this? If you propose a fix, please make it concise.
build_raw_request only auto-adds Content-Length for a non-empty body, so replacing the body with an empty string produced a request with no Content-Length. Set it to 0 explicitly in apply_modifications (scoped to the body-replacement path, so body-less requests like GET are unaffected). Adds a test.
@Osamaali313

Copy link
Copy Markdown
Author

Good catch — fixed in cd415e7. An empty replacement body now gets Content-Length: 0 set explicitly in apply_modifications, with a test.

I scoped it to the body-replacement path rather than changing build_raw_request's if body guard to if body is not None: the broader change would also attach Content-Length: 0 to genuinely body-less requests (e.g. replayed GETs that had no Content-Length originally), which would reduce replay fidelity — something a proxy used for security testing should avoid. Happy to switch to the guard change instead if you'd prefer it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants