[GH-ISSUE #2596] fix(browser): malformed Content-Length headers become numeric evidence #915

Closed
opened 2026-10-15 18:29:32 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2596

Summary

Response metadata turns malformed Content-Length headers into observed numeric lengths. A negative declaration becomes zero, hexadecimal becomes a decimal number, and exponent notation becomes a larger number. The capture must preserve an unknown value when the header does not declare a valid decimal length.

Runtime or environment

Source revision 8b181716ac, Node v26.10.0, npm 11.19.1, and locked dependencies. Tests exercised the helper and simulated CDP event ingestion, without launching Chrome.

Steps to reproduce

  1. Add a focused Vitest test beside CdpSafeMetadata.ts. Call safeResponseMetadata with request ID r, URL https://app.example.test/api, response {headers: {"Content-Length": value}}, and allowed origins containing https://app.example.test.
  2. Parameterize value independently as the strings "-5", "0x10", "1e3", and "+12". Require response.content_length to be null for each. Add controls for the strings "100" and "12abc", and an empty headers object; these should return 100, null, and null.
  3. To exercise ingestion, construct CdpCaptureEvents with inspectWebPageInputSchema.parse using endpoint http://127.0.0.1:9222, that approved origin, and target ID page. Supply new Set([origin]), where origin is the approved origin above, as the constructor's second argument. Call beginAuthorizedFrame("main"). Ingest Network.requestWillBeSent with requestId r, frameId main, timestamp 1, initiator type other, and a GET request to the approved URL. Ingest Network.responseReceived for r with that URL, status 200, mimeType text/plain, and each malformed header value. Require one retained responseMetadata entry and a null content_length.
  4. Run npm run test:focused -- src/browser/content-length.test.ts for the created test.

Expected behavior

A Content-Length header must declare decimal digits. An invalid negative, signed, hexadecimal, or exponent spelling does not establish a length and must remain null in normalized evidence. Valid decimal values and missing-header unknowns retain their existing behavior.

Actual behavior

Both executed paths returned 0 for -5, 16 for 0x10, 1000 for 1e3, and 12 for +12. All four malformed cases failed their null assertions. The helper controls returned 100 for 100 and null for 12abc or an absent header. The event accumulator retained exactly one response entry per case.

Evidence

  • Expected source: AGENTS.md, Architecture and Cleanup, requires format-aware normalization and explicit unknowns; src/domain/browserObservationSchemas.ts:241 defines nullable length metadata; RFC 9110 section 8.6 defines Content-Length as 1*DIGIT, https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6.
  • Failure source: src/browser/CdpSafeMetadata.ts:346-349 uses Number followed by truncation and clamping; src/browser/CdpCaptureEventHandlers.ts:376-415 admits tracked approved responses to that normalizer; src/browser/CdpPageCapture.ts:322-325 retains its output.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

No ingestion guard validates this header before normalization. Raw headers are discarded, so the resulting capture cannot recover the original spelling. The tests establish handling of these CDP inputs; they do not establish which malformed HTTP responses a particular browser will emit. No matching existing issue was found in read-only searches.

Restoration check

Repeat the four malformed values at both helper and event ingestion boundaries and require null without dropping the response entry. Preserve the valid decimal result 100 and absent-header null control. The capture must retain its other response metadata and must not invent a zero-length declaration for an invalid value.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded metadata parser creates numeric evidence that the input never declared, changing retained observations beyond wording. The tests establish the ingestion contract, not real-browser frequency.
  • Workaround status: none
  • Workaround basis: The normalized capture discards the raw header. Ignoring the length field loses requested metadata and cannot recover the correct observed-versus-unknown distinction.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2596 ## Summary Response metadata turns malformed Content-Length headers into observed numeric lengths. A negative declaration becomes zero, hexadecimal becomes a decimal number, and exponent notation becomes a larger number. The capture must preserve an unknown value when the header does not declare a valid decimal length. ## Runtime or environment Source revision 8b181716aca2cb467be499cba226abfb5ae19141, Node v26.10.0, npm 11.19.1, and locked dependencies. Tests exercised the helper and simulated CDP event ingestion, without launching Chrome. ## Steps to reproduce 1. Add a focused Vitest test beside CdpSafeMetadata.ts. Call safeResponseMetadata with request ID r, URL https://app.example.test/api, response {headers: {"Content-Length": value}}, and allowed origins containing https://app.example.test. 2. Parameterize value independently as the strings "-5", "0x10", "1e3", and "+12". Require response.content_length to be null for each. Add controls for the strings "100" and "12abc", and an empty headers object; these should return 100, null, and null. 3. To exercise ingestion, construct CdpCaptureEvents with inspectWebPageInputSchema.parse using endpoint http://127.0.0.1:9222, that approved origin, and target ID page. Supply new Set([origin]), where origin is the approved origin above, as the constructor's second argument. Call beginAuthorizedFrame("main"). Ingest Network.requestWillBeSent with requestId r, frameId main, timestamp 1, initiator type other, and a GET request to the approved URL. Ingest Network.responseReceived for r with that URL, status 200, mimeType text/plain, and each malformed header value. Require one retained responseMetadata entry and a null content_length. 4. Run npm run test:focused -- src/browser/content-length.test.ts for the created test. ## Expected behavior A Content-Length header must declare decimal digits. An invalid negative, signed, hexadecimal, or exponent spelling does not establish a length and must remain null in normalized evidence. Valid decimal values and missing-header unknowns retain their existing behavior. ## Actual behavior Both executed paths returned 0 for -5, 16 for 0x10, 1000 for 1e3, and 12 for +12. All four malformed cases failed their null assertions. The helper controls returned 100 for 100 and null for 12abc or an absent header. The event accumulator retained exactly one response entry per case. ## Evidence - Expected source: AGENTS.md, Architecture and Cleanup, requires format-aware normalization and explicit unknowns; src/domain/browserObservationSchemas.ts:241 defines nullable length metadata; RFC 9110 section 8.6 defines Content-Length as 1*DIGIT, https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6. - Failure source: src/browser/CdpSafeMetadata.ts:346-349 uses Number followed by truncation and clamping; src/browser/CdpCaptureEventHandlers.ts:376-415 admits tracked approved responses to that normalizer; src/browser/CdpPageCapture.ts:322-325 retains its output. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete No ingestion guard validates this header before normalization. Raw headers are discarded, so the resulting capture cannot recover the original spelling. The tests establish handling of these CDP inputs; they do not establish which malformed HTTP responses a particular browser will emit. No matching existing issue was found in read-only searches. ## Restoration check Repeat the four malformed values at both helper and event ingestion boundaries and require null without dropping the response entry. Preserve the valid decimal result 100 and absent-header null control. The capture must retain its other response metadata and must not invent a zero-length declaration for an invalid value. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A bounded metadata parser creates numeric evidence that the input never declared, changing retained observations beyond wording. The tests establish the ingestion contract, not real-browser frequency. - Workaround status: none - Workaround basis: The normalized capture discards the raw header. Ignoring the length field loses requested metadata and cannot recover the correct observed-versus-unknown distinction.
bsakaguchi 2026-10-15 18:29:32 +00:00
  • closed this issue
  • added the
    bug
    label
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#915
No description provided.