Skip to content

Hardening: input validation and bounds tightening across 36 subsystems (round 4) - #31339

Merged
Jarred-Sumner merged 96 commits into
mainfrom
claude/hardening-sweep-4
May 25, 2026
Merged

Hardening: input validation and bounds tightening across 36 subsystems (round 4)#31339
Jarred-Sumner merged 96 commits into
mainfrom
claude/hardening-sweep-4

Conversation

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator

Continues the hardening series (rounds 1–3) with another pass of input validation, bounds checking, and lifetime tightening across the codebase. 73 changes, each in its own commit, plus regression tests covering 55 of them (each test verified to fail on the released bun and pass on this branch).

Areas touched: install / lockfile / tarball extraction / bunx / upgrade, sql (postgres, sqlite), tls / sockets / dns, http2 / http3 / http client / server, markdown, shell, node:fs / zlib / spawn / streams, crypto, vm, yaml / semver / valkey / undici / url / cookies, dev server, transpiler cache, string handling.

The general shape of the changes: reject malformed or out-of-range inputs earlier, bound buffer and recursion growth, keep borrowed buffers alive (or copy them) for the duration of the operations that read them, and validate names/paths/headers before they are used to address files, hosts, or memory.

springmin pushed a commit to springmin/bun that referenced this pull request May 26, 2026
* oven/main (10 new commits):
  Optimize TextEncoder.encode: restore SIMD ASCII fast paths lost in the Rust port (oven-sh#31385)
  js_parser: sanitize auto-generated default export name for digit-named modules (oven-sh#31403)
  fetch: run checkServerIdentity before writing the request (oven-sh#31325)
  ffi: avoid copying the threadsafe callback wrapper on the calling thread (oven-sh#31332)
  install: gate the exit-callback cache teardown to the main thread (oven-sh#31376)
  fix(node:module): don't register native helpers as their own constructors (oven-sh#31393)
  css: escape custom pseudo-class/element names when printing (oven-sh#31404)
  Deepen the lots-of-for-loop fixture so the transpiler stack-overflow tests throw on Windows (oven-sh#31382)
  Hardening: input validation and bounds tightening across 36 subsystems (round 4) (oven-sh#31339)
  Speed up FormData multipart serialization (oven-sh#31379)

Auto-merged: src/install/PackageManager.rs, src/runtime/cli/upgrade_command.rs, src/runtime/webcore/Blob.rs, src/sys/lib.rs
Jarred-Sumner added a commit that referenced this pull request May 27, 2026
…s (round 6) (#31417)

Tightens input validation, bounds checking, and state handling across
the runtime, package manager, and CLI. Continuation of #31339; same
structure (small per-area commits, regression tests included).

### Package manager / CLI
- install: validate package folder names derived from dependency aliases
before extraction (non-git resolutions)
- install: require integrity for off-registry tarball URLs when
migrating `package-lock.json` (yarn.lock migration unchanged — its v1
workspace/github entries legitimately omit integrity)
- install: validate migrated git committish values as single path
components
- install: constrain transitive `file:` dependency targets to their
declaring package
- install: JSON-escape registry/git strings when saving `bun.lock`;
escape quoted scalars in the yarn.lock printer
- install: byte-compare string-pool hits in manifest parsing and bound
version writes
- install: key lifecycle-script trust on the declared dependency alias
and resolution type
- install: resolve bin link targets and skip entries that escape the
package directory
- install: bound cache-folder name formatting and tarball decompression
output
- bunx: re-validate cache directory ownership after creation
- run: resolve the package-script shell from the original PATH instead
of `node_modules/.bin`
- upgrade-related items intentionally not included

### HTTP / TLS / networking
- fetch: drop caller-supplied Transfer-Encoding for fixed-size bodies
(single framing header on the wire)
- fetch: exclude requests carrying custom TLS options from the
experimental HTTP/3 path
- node:http: validate `options.port` in ClientRequest
(ERR_SOCKET_BAD_PORT)
- node:http2: zero-fill outbound DATA frame padding
- node:dns: reject hostnames containing embedded NUL bytes (slightly
stricter than Node, which truncates at the NUL; never affects a valid
hostname)
- tls: re-establish per-loop BIO state before driving handshakes after
JS callbacks
- server: disarm request-body callbacks before handing the response to
the file-stream path
- server: restrict the development-mode `/bun:info` route to loopback
clients
- valkey: checkpoint partial-line scan progress; dev server: bound
error-report path normalization
- bun-vscode: bind the diagnostics socket to a fresh per-session path
and verify it before advertising

### Web / runtime APIs
- Blob/Body: copy content types into the Blob they describe; bound
deserialization lengths; serialize only a slice's own window; tolerate
odd-offset UTF-16 text decoding
- S3: validate the `type` option with the same check other Blob
constructors use
- FormData: handle duplicate index-like field names in serialization
- WebCrypto: refuse to serialize non-extractable CryptoKey material
through script-visible serializers
- node:crypto: fail closed on ECDH errors; stop after rejecting
unsupported RSA decryption padding
- node:fs: pin async write sources; bound recursive-readdir path joins
- SQL: guard column-identifier tags when building row objects
- escapeHTML: process lone surrogates without skipping the following
character

### Parsers / shell / misc
- shell: copy stdin redirect buffers up front; pin output redirect
buffers; treat interpolated `cd` arguments literally
- markdown: sanitize link/image/fence metadata in the ANSI renderer;
make emphasis resolution linear on adversarial input
- JSON5/JSONC: stack-checked AST conversion; YAML: bound merge-key
materialization
- CSS: clamp tokenizer advances at end of input; glob: derive entry
offsets from the joined path
- resolver: validate exports-map targets after wildcard substitution

### Tests
34 new regression tests across the touched areas, each verified to fail
on the released build and pass here. A few fixes have no standalone test
where the behavior difference is not observable from JS (noted
per-commit in the shard history); CI exercises the affected suites.

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

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
robobun added a commit that referenced this pull request Jul 9, 2026
…ompat

The Rust port of on_handshake (socket_body.rs) gained a
bun_boringssl::check_server_identity() call in #31339 that the Zig
reference (socket.zig onHandshake) never had. When the cert chain
verifies but the peer cert's SAN/CN does not cover the connect
hostname/servername, this flipped authorized to false, set a
HOSTNAME_MISMATCH flag, and passed success=false to the JS handshake
callback.

Downstream effects:
- tls.connect sets _secureEstablished = !!success, now false where
  Node and Bun 1.3.14 both report true
- Bun.connect socket.authorized is now false where Zig returned true
- socket.getAuthorizationError() returns an Error with the
  non-Node-standard code HOSTNAME_MISMATCH instead of null
- a user-supplied options.checkServerIdentity that intentionally
  accepts the mismatch can no longer make _secureEstablished/success
  true

Hostname verification is already performed in the JS layer
(src/js/node/net.ts) via the user-overridable checkServerIdentity
callback, which produces the Node-standard
ERR_TLS_CERT_ALTNAME_INVALID. The native layer should report only the
BoringSSL cert-chain verify result, matching the Zig reference.

Revert on_handshake and get_authorization_error to match the Zig
reference, drop the HOSTNAME_MISMATCH flag, and replace the test that
locked in the divergent behavior with one asserting Zig/Node
semantics. Add a node:tls test (verified against Node) that a
user-supplied checkServerIdentity returning undefined yields
_secureEstablished=true, authorized=true.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants