SIGN IN SIGN UP
oven-sh / bun UNCLAIMED

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one

0 0 150 Rust

Hardening: input validation and protocol tightening across 24 subsystems (round 7) (#31495)

Tightens input validation, bounds checking, protocol framing, and state
handling across the package manager, HTTP stack, sockets/TLS, SQL
clients, and parsers. Continuation of #31417 (round 6); same structure —
small per-area commits with regression tests included.

### Package manager / CLI
- install: validate extract folder names and dependency aliases for the
remaining resolution shapes; bounds-check resolution lookups during
lockfile loads
- install: trusted-dependency entries for non-npm resolutions only apply
when the dependency is declared by the root or a workspace; the security
scanner is also told about packages reached through non-npm parents
- install: registry auth tokens stay scoped to their configured host
(and are not carried across an https→http redirect)
- pm: `bun pm cache rm` resolves the cache directory from the process
environment, ignoring project-local overrides for the destructive delete
(`bun pm cache` prints the same path it would delete)
- pack: validate the name/version used to form the tarball filename
- compile: build artifacts are created exclusively with owner-only
modes; repl: the history file is created 0600 (and an existing one is
tightened)
- yarn.lock migration behavior is unchanged; a comment now documents the
intentionally lenient handling of entries without integrity

### HTTP / HTTP2 / WebSocket / S3
- fetch: never forwards a caller-supplied Content-Length that disagrees
with the actual body (node:http behavior unchanged); drains interim 1xx
bytes as they are parsed; never returns a connection with a framing
violation to the keep-alive pool
- node:http2: rejects requests carrying connection-specific headers,
repeated single-value/pseudo headers, or content-length/DATA mismatches
(verified against Node/nghttp2 behavior); copies queued DATA frames
before re-entrant writes; keeps parsing safe when a socket chunk's
buffer is transferred mid-frame
- Bun.serve: absolute-form request targets are routed by path with
`request.url` derived from Host; no message-body bytes are written for
null-body statuses (101/103/204/205/304) — Response construction is
unchanged
- websocket: handshake buffering survives client teardown from the open
handler
- S3: object keys keep `?`/`#` characters end-to-end; list-response
parsing is linear; the remote-address accessor copies into caller-owned
storage

### Sockets / TLS / SQL / runtime
- sql: an explicit `tls`/`ssl` option aborts the connection before
credentials are sent if the server declines TLS;
certificate-verification behavior is unchanged. Row construction is
bounded by the declared structure; MySQL rebuilds cached row shapes when
result columns change; postgres protocol counts are validated against
the received bytes
- node:tls: server sockets only report `authorized: true` after a client
certificate was requested and verified (matches observed Node behavior)
- sockets: handler reload and accepted-socket reuse re-validate
ownership before freeing; the TLS read path restores shared dispatch
state after re-entrant callbacks; pipe reads re-acquire the scratch
buffer per use
- sqlite: the cross-worker database registry and lazy library load are
lock-protected; spawned children close descriptors across the full fd
range
- crypto: encoded-hash cost parameters are bounded before verification;
errors: stack-frame callees stay GC-reachable while formatting

### Parsers / shell / node
- markdown: reference-definition lookup, table column counts, and
autolink scanning are linear/bounded
- YAML: alias expansion is budgeted in the parser used by imports and
the bundler
- node:fs: watcher path joins surface ENAMETOOLONG instead of aborting;
assert: diff output is bounded for large operands

### Tests
33 new regression tests across the touched areas (validated to fail on
the released build and pass here), plus a handful of regression-only
cases where the released build does not exhibit the behavior
deterministically. A few fixes have no standalone test where the change
is not observable from JS.

`cargo check` and the cross-target checks pass on all 10 CI targets; the
touched suites pass locally with no new failures versus main. The branch
is rebased on current main.

### Changes tried and reverted during review (rationale)
- **Lockfile lifecycle scripts** — an earlier commit re-derived
dependency lifecycle script text from each installed package's
`package.json` instead of the deserialized lockfile data; reverted
because `bun.lockb` intentionally stores and uses the script text, and
that design stays.
- **yarn.lock migration** — an earlier commit rejected off-registry
tarball URLs without integrity during migration; reverted because yarn
v1 lockfiles legitimately contain such entries (workspace, `file:`,
codeload) and migration must not fail closed. The lenient handling is
now documented with a comment at the site.
- **`Response` and null-body statuses** — both the body-dropping and the
later spec-style `TypeError` for non-null bodies with
101/103/204/205/304 were reverted: existing code and frameworks
(including Elysia) construct such responses and expect the body to be
ignored, so changing construction is a breaking change nobody asked for.
Only the wire-level behavior (no body bytes emitted) is kept.
- **SQL client TLS** — an earlier commit made an explicit `tls`/`ssl`
option imply certificate verification; narrowed to abort-on-decline only
because the unverified default for these options is intentional and
matches other JavaScript database clients.
- **node:http `path` with an absolute URI** — an earlier commit rewrote
such requests to a path-only target; removed because measured Node
behavior does not do that, and Node compatibility takes precedence.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
J
Jarred Sumner committed
002dd41eb37926407b43c8456b0d895ad97b7853
Parent: 843549b
Committed by GitHub <noreply@github.com> on 5/28/2026, 9:38:12 PM