Batch 9 (15): bun, bzflag (3), cake_wallet (4), calligra, caprice32 (2), cataclysm (3), cemu Batch 10 (15): cemu-0002, citra, clickhouse-java, cmake (3), cocos2d (3), conduit, cura (2), curaengine, clamav, contiki
3.2 KiB
Bun — CWE-407 Disclosure Brief (bun-0001)
2026-04-14 · Patch available — awaiting upstream merge
Finding
One O(n²) defect in Bun's Yarn lockfile parser. The populatePackageVersionMap() function performs a redundant second linear scan over a version list after the first scan already found the needed entry. Fires during bun install on every Yarn-format lockfile.
The Defect
bun-0001 (PATCHED — HIGH): src/install/yarn.zig:773
// In populatePackageVersionMap() — fires per package entry in yarn.lock:
for (list.items) |item| {
if (strings.eql(item.version, existing.version)) found_existing = true;
if (strings.eql(item.version, version)) found_new = true;
}
// ...
if (found_new) {
for (list.items) |item| { // O(M) second scan — redundant
if (strings.eql(item.version, version)) {
yarn_entry_to_package_id[yarn_idx] = item.package_id;
break;
}
}
}
The first pass already visits the matching item but discards package_id. A second O(M) scan then re-finds it. For lockfiles with many aliased versions of the same package, M grows large and the double-scan fires per entry.
Complexity Proof
At M=100 version entries per package name:
- Defective: 2 × 100 = 200 string comparisons per entry (two full scans)
- Fixed: 100 string comparisons per entry (single pass, capture
package_idinline) - 2× op reduction per package entry. Scales with lockfile size.
At M=1,000 (large monorepo lockfiles): 2,000 vs 1,000 comparisons per entry.
Impact
Bun serves millions of JavaScript developers. bun install processes Yarn lockfiles on every CI run and every developer workstation. Monorepo lockfiles with thousands of entries hit this path repeatedly. The redundant scan adds measurable overhead to package resolution in large projects.
The Fix
Capture package_id during the first scan, eliminating the second pass entirely:
// Before — two scans
for (list.items) |item| {
if (strings.eql(item.version, version)) found_new = true;
}
// ... later:
for (list.items) |item| { // redundant O(M) scan
if (strings.eql(item.version, version)) {
yarn_entry_to_package_id[yarn_idx] = item.package_id;
break;
}
}
// After — single scan
// CWE-407 fix: capture package_id in first pass, eliminate redundant second scan.
var found_package_id: Install.PackageID = 0;
for (list.items) |item| {
if (strings.eql(item.version, version)) {
found_new = true;
found_package_id = item.package_id;
}
}
// ... later:
yarn_entry_to_package_id[yarn_idx] = found_package_id;
Patch
Fix available: defects/bun/patch/bun-0001-yarn-version-single-pass.patch
Single-file patch on src/install/yarn.zig. Captures package_id during the existing scan loop, removes the redundant second loop.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (oven-sh/bun).
- Assess severity — fires on every
bun installwith Yarn lockfiles. - Coordinate a disclosure date — we target 90 days from first contact.
- We will credit the Bun team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.