Skip to content

Bun.serve: reject Transfer-Encoding on an HTTP/1.0 request (RFC 9112 6.1) - #35864

Merged
Jarred-Sumner merged 3 commits into
mainfrom
farm/4fd2b5b7/serve-reject-http10-transfer-encoding
Aug 13, 2026
Merged

Bun.serve: reject Transfer-Encoding on an HTTP/1.0 request (RFC 9112 6.1)#35864
Jarred-Sumner merged 3 commits into
mainfrom
farm/4fd2b5b7/serve-reject-http10-transfer-encoding

Conversation

@robobun

@robobun robobun commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Repro

import net from "node:net";
const server = Bun.serve({ port: 0, async fetch(req) { return new Response(await req.text()); } });
const c = net.connect(server.port, "127.0.0.1");
c.on("data", d => console.log(JSON.stringify(d.toString("latin1"))));
c.write("POST /a HTTP/1.0\r\nHost: x\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n0\r\n\r\n");

Before: HTTP/1.1 200 OK, handler invoked, body "hello" decoded from the chunked framing.

RFC 9112 6.1:

A server or client that receives an HTTP/1.0 message containing a Transfer-Encoding header field MUST treat the message as if the framing is faulty, even if a Content-Length is present, and close the connection after processing the message.

An HTTP/1.0 sender by definition does not implement Transfer-Encoding, so a proxy and backend that disagree on whether to honour it on a 1.0 message disagree on where the body ends.

Cause

fenceAndConsumePostPadded in packages/bun-uws/src/HttpParser.h validates Transfer-Encoding (TE+CL conflict, chunked-not-last, duplicate chunked) but never consults req->ancientHttp, so an HTTP/1.0 request with Transfer-Encoding: chunked passes every check and is parsed as chunked.

Fix

For Bun.serve (non-IsNodeHttp), return HTTP_PARSER_ERROR_INVALID_TRANSFER_ENCODING (400) when req->ancientHttp && transferEncoding.has, checked alongside the existing TE validity checks. node:http keeps llhttp's behaviour (dispatch and close): Node v26.3.0 dispatches such a request with httpVersion === "1.0" and the decoded body, and the HTTP/1.0 request already marks the connection for close via isAncient.

Verification

New tests in test/js/bun/http/request-smuggling.test.ts:

  • rejects Transfer-Encoding on an HTTP/1.0 request (default close and Connection: keep-alive variants): 400, handler never called. Both return 200 on main.
  • accepts Transfer-Encoding: chunked on an HTTP/1.1 request: control, still 200 with body "hello".
  • node:http dispatches Transfer-Encoding on an HTTP/1.0 request (llhttp parity): unchanged, matches Node.
bun bd test test/js/bun/http/request-smuggling.test.ts   # 79 pass, 0 fail

Related: #33878 (non-persistent pipelined dispatch), #35295 (TE lists), #33633 (DEL in header values). None of those reject the HTTP/1.0 + TE case.


[review] gate passed · iteration 6 · 2 files touched

fails on main (without fix)
ASAN without fix: 2 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/js/bun/http/request-smuggling.test.ts
bun test v1.4.0 (ba20a7ee9)

test/js/bun/http/request-smuggling.test.ts:
(pass) rejects multiple Transfer-Encoding headers with chunked [399.17ms]
(pass) rejects Transfer-Encoding with chunked not last [124.45ms]
(pass) rejects duplicate chunked in Transfer-Encoding [69.87ms]
(pass) rejects Transfer-Encoding + Content-Length [73.48ms]
185 |     client.on("data", data => (buf += data.toString("latin1")));
186 |     client.on("close", () => resolve(buf));
187 |     client.write(maliciousRequest);
188 |   });
189 | 
190 |   expect(response).toStartWith("HTTP/1.1 400 Bad Request\r\n");
                         ^
error: expect(received).toStartWith(expected)

Expected to start with: "HTTP/1.1 400 Bad Request\r\n"
Received: "HTTP/1.1 200 OK\r\ncontent-type: text/plain;charset=utf-8\r\nDate: Wed, 29 Jul 2026 06:18:12 GMT\r\nContent-Length: 2\r\n\r\nOK"

      at <anonymous> (/workspace/bun/test/js/bun/http/request-smuggling.test.ts:190:20)
(fail) rejects Transfer-Encoding on an HTTP/1.0 request (defa
... (truncated)

release without fix: 12 FAILED
bun test v1.4.0-canary.1 (1498d7b77)

test/js/bun/http/request-smuggling.test.ts:
(pass) rejects multiple Transfer-Encoding headers with chunked [7.84ms]
(pass) rejects Transfer-Encoding with chunked not last [1.91ms]
(pass) rejects duplicate chunked in Transfer-Encoding [2.50ms]
(pass) rejects Transfer-Encoding + Content-Length [2.67ms]
185 |     client.on("data", data => (buf += data.toString("latin1")));
186 |     client.on("close", () => resolve(buf));
187 |     client.write(maliciousRequest);
188 |   });
189 | 
190 |   expect(response).toStartWith("HTTP/1.1 400 Bad Request\r\n");
                         ^
error: expect(received).toStartWith(expected)

Expected to start with: "HTTP/1.1 400 Bad Request\r\n"
Received: "HTTP/1.1 200 OK\r\ncontent-type: text/plain;charset=utf-8\r\nDate: Wed, 29 Jul 2026 06:18:23 GMT\r\nContent-Length: 2\r\n\r\nOK"

      at <anonymous> (/workspace/bun/test/js/bun/http/request-smuggling.test.ts:190:20)
(fail) rejects Transfer-Encoding on an HTTP/1.0 request (default close) [2.69ms]
185 |     client.on("data", data => (buf += data.toString("latin1")));
186 |     client.on("close", () => resolve(buf));
187 |     client.write(malicious
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/js/bun/http/request-smuggling.test.ts
bun test v1.4.0 (ba20a7ee9)

test/js/bun/http/request-smuggling.test.ts:
(pass) rejects multiple Transfer-Encoding headers with chunked [367.37ms]
(pass) rejects Transfer-Encoding with chunked not last [118.62ms]
(pass) rejects duplicate chunked in Transfer-Encoding [61.39ms]
(pass) rejects Transfer-Encoding + Content-Length [75.57ms]
(pass) rejects Transfer-Encoding on an HTTP/1.0 request (default close) [98.03ms]
(pass) rejects Transfer-Encoding on an HTTP/1.0 request (Connection: keep-alive) [54.87ms]
(pass) accepts Transfer-Encoding: chunked on an HTTP/1.1 request [94.44ms]
(pass) node:http dispatches Transfer-Encoding on an HTTP/1.0 request (llhttp parity) [408.27ms]
(pass) rejects conflicting duplicate Content-Length headers [53.39ms]
(pass) accepts duplicate Content-Length headers with identical values [77.41ms]
(pass) rejects empty-valued Content-Length followed by smuggled Content-Length [59.97ms]
(pass) accepts valid Transfer-Encoding: chunked [62.79ms]
(pass) accepts valid Transfer-
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 752ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[0/105] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu)

  nightly-2026-07-20-x86_64-unknown-linux-gnu unchanged - rustc 1.99.0-nightly (9f36de775 2026-07-19)

�[1m�[92m   Compiling�[0m bun_md v0.0.0 (/workspace/bun/src/md)
�[1m�[92m   Compiling�[0m bun_ast v0.0.0 (/workspace/bun/src/ast)
�[1m�[92m   Compiling�[0m bun_io v0.0.0 (/workspace/bun/src/io)
�[1m�[92m   Compiling�[0m bun_uws v0.0.0 (/workspace/bun/src/uws)
�[1m�[92m   Compiling�[0m bun_zlib v0.0.0 (/workspace/bun/src/zlib)
�[1m�[92m   Compiling�[0m bun_brotli v0.0.0 (/workspace/bun/src/brotli)
�[1m�[92m   Compiling�[0m bun_dotenv v0.0.0 (/workspace/bun/src/dotenv)
�[1m�[92m   Compiling�[0m bun_install_types v0.0.0 (/workspace/bun/src/install_types)
�[1m�[92m   Compiling�[0m bun_parsers v0.0.0 (/workspace/bun/src/parsers)
�[1m�[92m   Compiling�[0m bun_react_compiler v0.0.0 (/workspace/bun/src/react_compiler)
�[1m�[92m   Compiling�[0m bun_css v0.0.0 (/workspace/bun/src/css)
�[1m�[92m   Compiling�[0m bun_options_types v0.0.0 (/wo
... (truncated)
diff hotspot
packages/bun-uws/src/HttpParser.h          |  20 +++++-
 test/js/bun/http/request-smuggling.test.ts | 102 +++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+), 3 deletions(-)

gate history · 4 passed · 0 rejected · iteration 6

evidence per changed file
file                                        reads  edits  tests
packages/bun-uws/src/HttpParser.h               5      3      0
test/js/bun/http/request-smuggling.test.ts      4      5      0

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

HTTP Transfer-Encoding handling

Layer / File(s) Summary
Parser state and framing validation
packages/bun-uws/src/HttpParser.h
Per-request HTTP version state is reset, and Bun.serve rejects HTTP/1.0 requests containing Transfer-Encoding.
Version-specific regression coverage
test/js/bun/http/request-smuggling.test.ts
Tests cover HTTP/1.0 rejection, HTTP/1.1 chunk decoding, and node:http parity.

Possibly related PRs

  • oven-sh/bun#32488: Related to deferred and validated Transfer-Encoding handling in the Node-compatible HTTP parser.
  • oven-sh/bun#32887: Related to chunked-body and trailer parsing in HttpParser.h.
  • oven-sh/bun#35295: Related to cross-version Transfer-Encoding validation and request-smuggling tests.

Suggested reviewers: jarred-sumner, cirospaciari

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: rejecting Transfer-Encoding on HTTP/1.0 requests in Bun.serve.
Description check ✅ Passed The description covers what changed and how it was verified, though it uses custom headings instead of the template's exact sections.

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator Author

Independently reproduced and landed on the same fix location (branch claude/farm-7342dd89-http10-te-reject). One difference: my diff folded req->ancientHttp into the existing transferEncoding.invalid predicate, so node:http also 400s (node v26.3.0 dispatches then closes; wire-level the default clientError still writes 400). Your !IsNodeHttp scoping is tighter on llhttp parity, so deferring to this PR and dropping my branch.

@robobun

robobun commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 5:05 AM PT - Jul 29th, 2026

@robobun, your commit ba20a7e has some failures in Build #84928 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 35864

That installs a local version of the PR into your bun-35864 executable, so you can run:

bun-35864 --bun

Comment thread packages/bun-uws/src/HttpParser.h
Comment thread test/js/bun/http/request-smuggling.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/bun-uws/src/HttpParser.h`:
- Around line 964-969: Add a regression test covering pipelined requests on one
connection: send an HTTP/1.0 keep-alive request followed in the same write by a
chunked HTTP/1.1 request, then assert the second request is dispatched and its
chunked body decodes correctly. Place the test alongside the existing HTTP
parser/connection tests and ensure it would fail if isAncientHTTP remains stale
between requests.

In `@test/js/bun/http/request-smuggling.test.ts`:
- Line 190: Strengthen the response assertions in
test/js/bun/http/request-smuggling.test.ts at lines 190, 217, and 249: replace
substring containment checks with assertions that the response starts with the
exact status lines “HTTP/1.1 400 Bad Request\r\n”, “HTTP/1.1 200 OK\r\n”, and
“HTTP/1.1 200 OK\r\n” respectively.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 59a31107-ee7e-4c82-a309-2c96069fc922

📥 Commits

Reviewing files that changed from the base of the PR and between 44f6469 and 8ad1bfb.

📒 Files selected for processing (2)
  • packages/bun-uws/src/HttpParser.h
  • test/js/bun/http/request-smuggling.test.ts

Comment thread packages/bun-uws/src/HttpParser.h
Comment thread test/js/bun/http/request-smuggling.test.ts Outdated

@claude claude Bot left a comment

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.

Both of my earlier findings (per-request ancientHttp reset, node:http test try/finally) are addressed in 8ad1bfb, and the toStartWith tightening in 1561d2d looks right. I didn't find anything new, but this edits the core uWS HTTP request parser on a smuggling-relevant path, so worth a human look.

What was reviewed:

  • The new !IsNodeHttp && ancientHttp && transferEncoding.has guard — strictly tightens (only rejects more), placed alongside the sibling TE checks, node:http path unchanged.
  • The unconditional isAncientHTTP = requestLineResult.isAncientHTTP write — only reached after a successful request-line parse (short-read/error return earlier), and its only other consumer (the Host-required check) becomes correctly stricter for a pipelined 1.1-after-1.0 request.
  • Tests: 400 + handler-not-called for both HTTP/1.0 variants, HTTP/1.1 control still 200 with decoded body, node:http parity preserved, server cleanup on all paths.
Extended reasoning...

Overview

Two-file change: packages/bun-uws/src/HttpParser.h adds a guard in fenceAndConsumePostPadded that rejects any HTTP/1.0 request carrying a Transfer-Encoding header (Bun.serve only, via !IsNodeHttp), and changes getHeaders to write isAncientHTTP unconditionally instead of only latching it to true. test/js/bun/http/request-smuggling.test.ts adds four tests (two 1.0 rejection variants, an HTTP/1.1 control, and a node:http llhttp-parity check).

Security risks

This is a request-smuggling hardening in the HTTP/1 wire parser. The new guard is monotonically stricter for Bun.serve — it can only cause additional 400s, never accept a request that was previously rejected — and the RFC 9112 6.1 citation is accurate. The node:http path is explicitly excluded so llhttp parity is preserved (verified by the new test). The unconditional isAncientHTTP write fixes a latent staleness I flagged in the first pass; its only pre-existing in-loop consumer was the Host-required check, which now correctly requires Host on a pipelined HTTP/1.1 request following an HTTP/1.0 one (previously it was wrongly exempt). No new attack surface is introduced.

Level of scrutiny

High. packages/bun-uws/src/HttpParser.h is the vendored uWS HTTP/1 request parser that fronts every Bun.serve connection, and the change sits in the Transfer-Encoding / framing validation block that exists specifically to prevent request smuggling. Even though the change is small and strictly-tightening, edits here warrant a maintainer's eyes.

Other factors

All prior review threads are resolved: my two findings were fixed in 8ad1bfb, CodeRabbit's toStartWith request was applied in 1561d2d, and CodeRabbit withdrew its pipelined-regression-test request after the author explained it would conflict with #33878. The gate evidence in the PR body shows the new tests fail on main and pass on the PR under both ASAN-debug and release. I confirmed ancientHttp/isAncientHTTP has no consumers outside HttpParser.h, and the unconditional write is only reached after consumeRequestLine succeeds (error/short-read paths return before it), so it never clobbers state with an indeterminate value.

@robobun

robobun commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator Author

CI build 84928 (rebased head ba20a7e) finished: 194 jobs passed, 2 expired, 0 test failures. test/js/bun/http/request-smuggling.test.ts is green on every lane. Every annotation is yellow (passed on retry or passed alone) and in unrelated areas: fs.watch leak threshold, s3/shell/streams leak counts, spawn-streaming-stdout, napi string encoding, terminal ConPTY, watch-many-dirs EISDIR, and a handful of parallel-batch-only flakes. The two expired jobs never received an agent.

Ready for review.

@claude claude Bot left a comment

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.

Both earlier findings (stale ancientHttp across pipelined iterations, and the node:http test's server leak on the reject path) are addressed in 8ad1bfb, and the toStartWith tightening from CodeRabbit is in. No new issues found — deferring only because this is the HTTP/1 parser's request-smuggling gate and the !IsNodeHttp scoping is a Node-compat policy call worth a maintainer nod.

What was reviewed:

  • getHeaders now writes isAncientHTTP unconditionally on the success path; short-read/error paths return before the TE check consumes it, so no stale read remains.
  • New rejection is scoped to !IsNodeHttp and gated on transferEncoding.has (any TE, not just chunked) — matches RFC 9112 6.1's "containing a Transfer-Encoding header field".
  • Control test confirms HTTP/1.1 chunked still 200s; node:http parity test wrapped in try/finally.
Extended reasoning...

Overview

Two-file change: a 3-line rejection in packages/bun-uws/src/HttpParser.h (fenceAndConsumePostPadded) that 400s any HTTP/1.0 request carrying a Transfer-Encoding header for Bun.serve, plus a supporting fix making getHeaders write isAncientHTTP unconditionally (previously latched true). Four new tests in request-smuggling.test.ts: two rejection variants (default-close and Connection: keep-alive), an HTTP/1.1 positive control, and a node:http llhttp-parity test.

Security risks

This is a security hardening — it narrows accepted input per an RFC 9112 6.1 MUST, closing a proxy/backend framing-disagreement vector. The only regression risk is over-rejection. I checked: the gate is !IsNodeHttp && req->ancientHttp && transferEncoding.has, so (a) node:http keeps llhttp's dispatch-then-close behaviour, (b) only genuine HTTP/1.0 request-lines trigger it, and (c) after 8ad1bfb the per-request ancientHttp is written fresh on every getHeaders success, so a pipelined HTTP/1.1 request behind an HTTP/1.0 one no longer inherits a stale true. On the short-read/error branches getHeaders returns before the caller reaches the TE check, so the unwritten out-param there is harmless.

Level of scrutiny

High — this is the HTTP/1 request parser's smuggling-defence block, and the change alters which requests reach user handlers. That said, the diff is ~10 effective lines, follows the exact pattern of the adjacent TE+CL / chunked-not-last rejections, cites the governing RFC clause, and is covered by tests that fail on main and pass on the branch (per the gate evidence in the PR body).

Other factors

All prior review threads are resolved: my two inline findings from the first pass were fixed in 8ad1bfb, and CodeRabbit's toStartWith tightening landed in 1561d2d (its pipelined-regression-test request was withdrawn with a reasonable justification about #33878). CI didn't run tests due to a fleet-wide build-cpp scheduling stall unrelated to this diff. I'm deferring rather than approving because the !IsNodeHttp scoping (Bun.serve rejects, node:http dispatches-then-closes) is a Node-compat policy decision a maintainer should confirm, and HTTP parser changes in the smuggling path warrant a human sign-off even when they look correct.

robobun added 3 commits July 29, 2026 06:02
…6.1)

A POST /x HTTP/1.0 request with Transfer-Encoding: chunked was accepted,
the body decoded as chunked, and the handler invoked. RFC 9112 6.1 says a
server that receives an HTTP/1.0 message containing a Transfer-Encoding
header field MUST treat the message as if the framing is faulty and close
the connection after processing it.

Bun.serve now rejects such a request with 400 Bad Request before dispatch,
consistent with the existing strict rejections for TE+CL conflicts and
non-chunked TE values. node:http is unchanged: llhttp dispatches the
request and the HTTP/1.0 connection already closes after.
…e:http test server

getHeaders previously only set isAncientHTTP to true, never back to false,
so a pipelined HTTP/1.1 request in the same recv buffer after an HTTP/1.0
one saw a stale ancientHttp and the new Transfer-Encoding check would
wrongly 400 it. getHeaders now writes the flag unconditionally.

The node:http parity test now closes its server in a finally so a rejected
client promise cannot leak the listening server.
@robobun
robobun force-pushed the farm/4fd2b5b7/serve-reject-http10-transfer-encoding branch from dd9f4e2 to ba20a7e Compare July 29, 2026 06:08
@robobun

robobun commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto main (ba20a7e, was 32 commits behind) and dropped the empty retrigger commit. request-smuggling.test.ts 79/79 pass locally on the rebased build; fail-before still holds on the released canary. The previous build's only red was step-failed-outside-runner on the linux build-bun jobs (pre-existing on main) plus unrelated retry-green flakes. Waiting on CI.

@claude claude Bot left a comment

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.

No issues found — both earlier review points (per-request ancientHttp reset, try/finally around the node:http test server) are addressed and the assertions were tightened to toStartWith. Deferring to a human because this is a change to the HTTP/1.x request parser's framing validation.

What was reviewed:

  • The new !IsNodeHttp && req->ancientHttp && transferEncoding.has rejection sits alongside the existing TE validity checks and only tightens validation (fail-closed).
  • isAncientHTTP is now written unconditionally after consumeRequestLine succeeds; short-read paths return before the assignment, and each consumePostPadded call constructs a fresh HttpRequest, so no stale state persists across recv boundaries.
  • Tests: await using / try-finally cleanup, error wired to reject, close-buffered response, handlerCalled negative assertion, HTTP/1.1 control case, node:http parity.
Extended reasoning...

Overview

Two-file change: (1) packages/bun-uws/src/HttpParser.h gains a ~3-line check rejecting any HTTP/1.0 request that carries a Transfer-Encoding header (RFC 9112 §6.1) for the Bun.serve personality, plus a change to write isAncientHTTP unconditionally in getHeaders so a pipelined HTTP/1.1 request in the same recv buffer after an HTTP/1.0 one is not mis-classified; (2) four new tests in test/js/bun/http/request-smuggling.test.ts covering the 400 rejection (both default-close and Connection: keep-alive), an HTTP/1.1 control, and node:http parity with llhttp.

Security risks

This is request-smuggling hardening. The change is purely additive on the rejection side — it introduces a new 400 path for a spec-invalid combination and cannot loosen framing. The only theoretical risk was a false-positive rejection of a valid HTTP/1.1 request via a stale ancientHttp flag, which was raised in the first review pass and fixed by making getHeaders write the flag unconditionally. I re-traced the short-read paths: on request-line short-read getHeaders returns before the assignment, and on header short-read the flag is written correctly then re-derived on the retry from a fresh stack-allocated HttpRequest, so no stale state crosses recv calls. The node:http path (IsNodeHttp) is deliberately excluded to preserve llhttp parity, and the HTTP/1.0 request already sets nodeHttpSawConnectionClose / HTTP_CONNECTION_CLOSE so the connection closes afterward.

Level of scrutiny

High — HttpParser.h is the wire-level framing validator for every Bun.serve connection, and this file's history is a sequence of request-smuggling fixes. Even though the diff is small and fail-closed, changes here warrant a maintainer's eyes.

Other factors

Both of my earlier inline findings were addressed in 5befe25 (unconditional isAncientHTTP write; try/finally around the node:http server). CodeRabbit's toStartWith tightening was applied in ba20a7e; its pipelined-regression request was declined with a stated reason (would conflict with #33878 and doesn't fail on main). The mechgate evidence in the PR description shows the two rejection tests fail on main and pass with the fix; the release-without-fix run shows the HTTP/1.1 control and node:http parity tests pass on main, so they are true controls. CI on the previous build was green on every lane that received a binary. No bugs surfaced in this run's bug-hunt.

@Jarred-Sumner
Jarred-Sumner merged commit bdb7382 into main Aug 13, 2026
52 of 54 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the farm/4fd2b5b7/serve-reject-http10-transfer-encoding branch August 13, 2026 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants