Skip to content

Passthrough conversation stripping leaves stale Content-Length #335

Description

@leseb

Bug Description

responses_proxy strips the Responses-only conversation field from passthrough request bodies when no ResponsesState was produced, but it does not update or remove Content-Length. The forwarded body is shorter than the original client body while the original framing header can remain in effect, which is request-smuggling-sensitive at this network proxy boundary.

Evidence

  • apis/src/openai/responses/proxy/mod.rs:170-173 — no-ResponsesState passthrough calls strip_conversation_field(body) and returns Continue.
  • apis/src/openai/responses/proxy/mod.rs:200-214strip_conversation_field removes conversation and rewrites body.
  • apis/src/openai/responses/proxy/mod.rs:185-188 — only the normal rebuild path pushes a replacement content-length matching the serialized body.
  • apis/src/openai/responses/proxy/tests.rs:322-336 — existing passthrough test proves body mutation but does not assert Content-Length behavior.

Steps to Reproduce

  1. Send a POST /v1/responses request through responses_proxy without a ResponsesState extension.
  2. Include a JSON body containing a top-level conversation field and a Content-Length equal to the original body length.
  3. Let on_request_body process the terminal buffered body.
  4. Observe that the body has conversation stripped, but no replacement/removal for Content-Length is emitted in this path.

Expected Behavior

When the passthrough path mutates the request body, it should either set Content-Length to the new body.len() or remove the original header so framing is recalculated. It should not leave a stale client-provided content length after shortening the body.

Actual Behavior

The no-ResponsesState path mutates body via strip_conversation_field and then returns Continue without updating request headers. Only the normal ResponsesState rebuild path pushes a replacement content-length.

Recommendation

Make strip_conversation_field report whether it mutated the body and the new length, then update the forwarded Content-Length through the same header-setting/removal mechanism used by body rebuilds. Add a regression test with an original Content-Length and a stripped conversation field asserting the final header state matches the rewritten body.

Clawpatch Metadata

  • Run: 20260713T070409-156e2c
  • Finding: fnd_sig-feat-apis-src-no-token-usage_84f43ba5fe
  • Severity: medium
  • Category: security
  • Confidence: high

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrustPull requests that update rust code

    Type

    Fields

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions