Repository navigation
Conversation
… Math.min parserOnHeadersComplete clamps the header count with Math.min, which user code can replace. A replacement that returns a different value makes _addHeaderLines read past the flat [name, value, ...] header array and matchKnownFields then throws an uncaught TypeError for every response. Use the $min intrinsic, which is the engine's own copy of Math.min.
|
Warning Review limit reached
On-demand reviews are free for the next 28 days. After that, they cost $0.25 per reviewed file. Or wait 6 minutes for your next included review. View limit detailsLimit details: You’ve used all 5 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
Status: reproduced on stock 1.4.0 with the standalone script from the report (load |
There was a problem hiding this comment.
LGTM — one-token swap to the $min intrinsic, matching the pattern already used across src/js/ and Node's own MathMin primordial at the same site.
What was reviewed
- Confirmed
$minis a declared JSC link-time constant (src/js/builtins.d.ts:542) with wide existing use ininternal/fs/streams.ts,util/inspect.js, andnative-readable.ts. - Test isolates the
Math.minmutation in a subprocess, usesport: 0/bunEnv, drains all pipes concurrently, and wiresuncaughtExceptionso the pre-fixTypeErrorproduces a nonzero exit — it fails for the right reason on the unfixed build. - Checked
parserOnHeaders(the sibling slow-path) — it clamps via subtraction/comparison, notMath.min, so no parallel site to fix.
Extended reasoning...
Overview
Single-character-class change in src/js/node/_http_common.ts: Math.min(n, maxHeaderPairs) → $min(n, maxHeaderPairs). $min is a JSC private-name intrinsic bound at bytecode compile time to the engine's own Math.min, so a userland reassignment of Math.min can no longer skew the header-pair clamp and push _addHeaderLines past the end of the flat header array. The accompanying test lives in the existing node-http-primoridals.test.ts, which is already the file for node:http tamper-resistance coverage.
Security risks
None introduced. The change removes a userland-influenceable call from a built-in module hot path, which is the direction the repo's tamper-resistance guidance requires for src/js/. No new inputs, no new surface.
Level of scrutiny
Low. This is the canonical primordial-safety pattern ($-prefixed intrinsic replacing a live global lookup). $min is declared in builtins.d.ts and already used at a dozen-plus sites (internal/util/inspect.js, internal/fs/streams.ts, internal/streams/native-readable.ts). Node's upstream lib/_http_common.js uses MathMin at the identical line, so this also tightens Node compat.
Other factors
- The test spawns a subprocess so the
Math.minmonkey-patch cannot leak into other tests, usesawait usingfor the process handle, drainsstdout/stderr/exitedwithPromise.all, and asserts stdout beforeexitCode— all per harness conventions. - The
uncaughtExceptionhandler in the fixture prints the message and exits 1, so the pre-fix behavior (uncaughtTypeError: undefined is not an objectfrommatchKnownFields) yields a distinct, non-timeout failure. - I checked the neighboring
parserOnHeadersslow path in the same file for the same bug class; it bounds viacapacity >= headers.lengtharithmetic rather thanMath.min, so there is no sibling site left unfixed. - No prior reviewer comments to address; timeline contains only a CodeRabbit rate-limit notice.
|
Updated 11:28 PM PT - Aug 23rd, 2026
✅ @robobun, your commit 5b4f9e3c05d5ae557760d2b35a0dc86757f821ed passed in 🧪 To try this PR locally: bunx bun-pr 40290That installs a local version of the PR into your bun-40290 --bun |
Problem
Math.minthat changes its result makes everynode:httpresponse throw an uncaughtTypeError: undefined is not an object (evaluating 'field')frommatchKnownFields(_http_incoming.ts). Bun 1.3.14 and Node v26 are not affected.parserOnHeadersCompleteinsrc/js/node/_http_common.ts:125clamps the header count with the liveMath.min. WithMath.minoff by one,_addHeaderLinesreads one pair past the end of the flat[name, value, ...]header array and passesundefinedas a field name.Fix
$min, the@minlink-time constant. It is the engine's own copy ofMath.minand user code cannot reach it. This is the same constructinternal/fs/streams.tsalready uses.MathMinprimordial inlib/_http_common.js.test/js/node/http/node-http-primoridals.test.ts(new test, fails on stock 1.4.0). Alsonode-http.test.ts,node-http-parser.test.ts,node-http-maxHeaderSize.test.ts, and the upstreamtest-http-max-headers-count.js/test-http-parser*.js.Background
maxHeaderPairsis the parser-side cap that implementsserver.maxHeadersCount. It bounds how many header pairs theIncomingMessagematerializes.$-prefixed name insrc/jsis a JSC private name.$minresolves at bytecode compile time to a function object the runtime created at global object init, not through a property lookup onMath.node:http, then setMath.min = (...a) => orig(...a) + 1and run onehttp.getagainst a local server.[stamp-90s] gate passed · iteration 0 · 2 files touched
fails on main (without fix)
passes on PR (with fix)
diff hotspot
gate history · 1 passed · 0 rejected · iteration 0
evidence per changed file