oven-sh/bun
The dominant risk class is memory safety across a Rust/C++/JSC boundary where `unsafe` is routine, raw pointers are stored across event-loop turns, and GC interaction is manual — `REVIEW.md` names this the most-blocked review category. Security-sensitive paths include registry credential handling, lifecycle scripts and the out-of-process security scanner, runtime C compilation via TinyCC, `Bun.secrets` keychain access, S3 SigV4 signing, CSRF token HMACs, the dev server's Host-header check, and the self-upgrade download path. Fragile coupling shows up where a value must stay in sync with an out-of-repo consumer (crash-report tag chars and `bun.report`) or with generated code. Blast-radius hotspots are the very large single files: `bundle_v2.rs` (8,079 lines), `VirtualMachine.rs` (7,700), `DevServer.rs` (6,792), `RequestContext.rs` (4,794), `server/mod.rs` (4,372).
- `Run::start` holds the JSC API lock in a guard that is never dropped, justified only by the function's `-> !` return type — any future refactor that makes it return would leak or double-release the lock.
- The run path deliberately leaks the entry path (`Box::leak(entry_path)`) because `vm.main` stores a raw backref into it and the hot reloader also retains it; correctness depends on the process never unwinding out of `start()`.
- CPU/heap profiler config casts `ctx`-owned `Box<[u8]>` borrows to `'static` through `std::ptr::from_ref`, relying on the context being process-lifetime — a lifetime erasure that is correct only for this one caller.
- `Tag::char()` must stay byte-for-byte in sync with a decoder in a separate repository (`oven-sh/bun.report`), and the comment pins a specific commit URL — a silent cross-repo coupling where adding a command breaks crash-report demangling with no local test.
- Crash reports are uploaded to a default remote base URL (`https://bun.report`) encoding the command tag, platform, and address trace; there is an override and a disable path, but the default is outbound network on crash.
- Registry credentials are parsed from `_authToken` segments and from bunfig scope objects into a single `NpmRegistry` value, meaning a bunfig or `.npmrc` parsing bug is directly a credential-disclosure or credential-confusion risk across registries.
- `bun install` executes arbitrary package-authored lifecycle scripts via `bun_spawn`, gated by a `trustedDependencies` allowlist plus a checked-in `default-trusted-dependencies.txt` — the allowlist is the only thing between an install and arbitrary code execution.
- The security scanner runs third-party scanner modules in a child process communicating over fds 3 and 4; the child reads the packages JSON to EOF and a write failure only prints to stderr and exits 1, so protocol-level failures depend on the parent correctly distinguishing scan failure from clean scan.
- `bun:ffi` compiles and executes attacker-influenced C at runtime through a vendored TinyCC fork, and `dlopen`s arbitrary shared libraries — an intentional capability with no sandbox, so any path that lets untrusted input reach `Bun.FFI.cc` is a full compromise.
- `bun upgrade` downloads release tarballs from GitHub, verifies a `sha256:` digest only when `version.digest.tag.is_supported()`, and additionally shells out to an external verify step — so an unsupported digest tag silently degrades integrity checking to whatever the verify subprocess does.
- The dev server's `is_allowed_host_header` allows any bare IP literal as a Host value; combined with binding to a non-loopback address this widens the accepted origin set beyond the configured hostname.
- CSRF tokens are HMAC-signed with a caller-supplied secret and an optional `session_id`; an empty `session_id` slice explicitly means the token is bound to no principal, so a caller omitting it produces tokens valid for any session.
- Analytics are on by default and gated by a `TriState` plus the `DO_NOT_TRACK` env var, with a packed feature bitset recording which APIs a run touched — telemetry that is opt-out rather than opt-in.
- Five files exceed 4,000 lines and concentrate blast radius: `bundle_v2.rs` (8,079), `VirtualMachine.rs` (7,700), `DevServer.rs` (6,792), `RequestContext.rs` (4,794), and `server/mod.rs` (4,372); a change in any one touches most of a subsystem's invariants at once.
- `RequestContext` cannot express its transport type through Rust's type system (the handle type varies with `(ssl_enabled, http3)` and stable Rust can't drive an associated type from a const-generic bool), and the file documents an abandoned trait-based approach — a known-fragile generic design that future transports must work around.
- Dead code is policed by an external cross-crate analyzer (`hawk.toml`) configured to union reachability across all 11 shipped targets through a throwaway `bun_hawk_root` binary, implying ordinary `cargo` dead-code lints do not catch unreachable code in this workspace.