Bun audit finds 13,365 unsafe Rust sites, most may be removable
Bun counted 13,365 unsafe Rust sites in its unreleased port, and about 9,300 look removable without major slowdown.

Bun’s Rust rewrite is carrying 13,365 unsafe sites, but the more interesting number is the one underneath it: about 9,300 of them, or 69.4%, may be removable without taking a big performance hit. The audit page is dated May 21, and Bun says the Rust port has not shipped in a released build yet, so users running Bun today are still on the original Zig implementation.
The audit reads like a working map of where unsafe accumulates during a serious systems rewrite. Bun broke the codebase into 774 files across 51 subsystems and counted every unsafe site with ripgrep before classifying each one by what it would take to eliminate it. Of the 13,365 sites, 6,274 need no slowdown to remove, 2,184 would need one extra check, 822 would need redesign, 3,097 are consolidated unsafe sites, and 988 are correct as-is. Bun says roughly 4,000 sites, or 30.6%, will likely remain unsafe, and about 3% of the total exists for performance reasons.

The biggest pile comes from Zig-era ownership patterns that carried over into the port, which account for 4,530 sites. The FFI boundary adds another 3,986, spanning JavaScriptCore, uWebSockets, uSockets, libuv, BoringSSL, c-ares, zlib, libarchive, lol-html, and mimalloc. Bun also points to 1,413 event-loop callback sites, 1,411 lifetime workarounds, 715 already-wrapped sites, 490 platform syscalls, 412 performance optimizations, and 408 GC-related sites. That breakdown is the part Rust tinkerers can copy: most unsafe did not arrive as one giant mistake, it arrived as a pile of narrow compromises that quietly stayed in place.

The audit also surfaced real soundness bugs, not just cleanup candidates. GitHub issue #30816 says PathString::init and slice() are unsound and that Miri reproduces undefined behavior from a safe API surface. A duplicate issue, #30719, shows a safe-Rust reproducer where dropping the backing allocation and then calling slice() produces a dangling slice. Bun maintainers said the fix should make PathString::init and a parallel hole in dir_iterator::next() into unsafe fn with documented outlives contracts, and that about 70 in-tree call sites were audited with per-site SAFETY comments. They also said the patch closed a file-descriptor leak in the resolver, while a pre-existing v8-heap-snapshot.test.ts SIGKILL flake was unrelated.
That is the cleanest lesson in the audit: unsafe is not just a count to grind down, it is a contract boundary to justify or delete. Bun’s comparison with Deno drives the point home, showing how density shifts when code sits close to a C boundary. The port is large, but the audit shows exactly where the sharp edges are, and which ones are still worth filing down before the Rust rewrite reaches a release build.
This article was produced by Prism’s automated news system from verified source data, official records, and press releases, then run through automated quality and moderation checks before publishing. The system is built and supervised by the people who set the standards it runs under. Read our full AI policy.
Did this article answer your question?


