Component: bun.lock
Severity (assessment): INFORMATIONAL
CWE: CWE-1104 (Use of Unmaintained/Vulnerable Third Party Components)
Related: #539
fastify is one of only two hard runtime dependencies (package.json:238-241). The lockfile resolves it to 5.10.0, whose transitive router (find-my-way@9.6.0) and URI parser (fast-uri@3.1.0 / 4.1.0) are all at versions with published HIGH advisories. Nothing in the ten workflows queries an advisory database, so the lockfile can sit on known-vulnerable versions indefinitely with every gate green.
Exploit walkthrough
Preconditions vary by advisory and by how the consumer resolves. Most direct: find-my-way is the router behind FastifyBackend, which is the framework's default HTTP backend. GHSA-c96f-x56v-gq3h is remotely triggerable by any client that can open an HTTP/2 connection to an actor-ts HTTP server — no authentication needed — and degrades the router into a CPU-bound state. fast-uri's host-confusion advisories matter wherever a parsed authority is used for a trust decision (origin checks, redirect validation, schema $ref resolution inside ajv, which fastify uses for request-body validation).
Honest scoping of who is actually exposed: consumers installing actor-ts from npm do NOT receive bun.lock — they resolve fastify: ^5.10.0 fresh and today would get 5.11.0 with patched transitives. The parties genuinely running the vulnerable versions are (a) this repository's own CI, including the prepublishOnly test run inside the credential-bearing publish job, (b) every Docker integration runner (tests/integration/**/Dockerfile.runner, all of which RUN bun install), (c) any consumer with a pinned or mirrored resolution, and (d) anyone who clones and runs the framework. The finding is therefore about the absence of a detection mechanism as much as the specific versions.
Evidence — bun.lock
Queried the npm advisory bulk endpoint (https://registry.npmjs.org/-/npm/v1/security/advisories/bulk, read-only POST) with the 294 distinct name@version pairs parsed out of bun.lock. Results inside the RUNTIME closure — computed by walking bun.lock from dependencies = {fastify, ts-pattern} only (50 packages):
HIGH find-my-way@9.6.0 vulnerable <=9.6.0 DDoS with HTTP2 GHSA-c96f-x56v-gq3h
HIGH fast-uri@3.1.0 vulnerable <=3.1.0 path traversal via percent-encoded dot segments GHSA-q3j6-qgpj-74h6
HIGH fast-uri@3.1.0 vulnerable <=3.1.1 host confusion via percent-encoded authority delims GHSA-v39h-62p7-jpjc
HIGH fast-uri@3.1.0 vulnerable >=3.0.0 <3.1.3 host confusion via failed IDN canonicalization GHSA-4c8g-83qw-93j6
HIGH fast-uri@3.1.0/4.1.0 vulnerable <=3.1.3 / >=4.0.0 <=4.1.0 host confusion via literal backslash GHSA-v2hh-gcrm-f6hx
Dev-tree only (not shipped to consumers, but present in every CI run and every prepublishOnly test run):
HIGH @fastify/static@10.1.0 route guard bypass via path traversal GHSA-83w8-p2f5-377r
MODERATE @fastify/static@10.1.0 authz bypass via non-canonical URL paths GHSA-8pvw-jcv7-9cmj
HIGH ws@8.20.0 memory exhaustion DoS from tiny fragments GHSA-96hv-2xvq-fx4p
MODERATE ws@8.20.0 uninitialized memory disclosure GHSA-58qx-3vcg-4xpx
HIGH/MOD brace-expansion@5.0.5 3 DoS advisories GHSA-mh99-…, -3jxr-…, -jxxr-…
MODERATE @hono/node-server@2.0.9 unauth. memory-leak DoS via aborted WS handshake GHSA-9mqv-5hh9-4cgg
MODERATE qs@6.15.1 / LOW body-parser@2.2.2
Fixed versions all exist today: fastify 5.11.0, find-my-way 9.7.0, fast-uri 4.1.2, ws 8.21.1, @fastify/static 10.1.2, @hono/node-server 2.0.12 (queried live from the registry).
No scan step exists anywhere — grepping .github/ for audit|snyk|osv|codeql|scorecard|trivy|dependency-review returns only prose in ISSUE_TEMPLATE/security_report.yml and a comment in integration-brokers.yml.
Note on @fastify/static: it is a devDependency and NOT a peerDependency (package.json:117), and src/http/static/StaticFiles.ts:3 documents that the framework deliberately does not use it — so those two advisories are dev-surface only.
Why the existing guard does not cover it
Dependabot runs daily against / (dependabot.yml:6-12) with minor and patch grouped, so fastify bumps do get PR'd. But Dependabot version updates operate on package.json ranges, and ^5.10.0 already admits 5.11.0 — and per the project's own documented experience (docs-checks.yml:41-46: "Dependabot bumps docs/package.json but never regenerates docs/bun.lock"), the Bun lockfile is not maintained by that flow at all. The lockfile-sync job (docs-checks.yml:47-60) catches lockfile/manifest DRIFT, which is a different property from lockfile FRESHNESS against advisories: a lockfile can be perfectly in sync with its manifest and still pin four HIGH-severity transitive versions, which is exactly the current state. Nothing anywhere queries an advisory database.
Suggested fix
Refresh the lockfile (bun update fastify / bun install to pull find-my-way ≥9.7.0 and fast-uri ≥4.1.2, plus ws ≥8.21.1, @fastify/static ≥10.1.2, @hono/node-server ≥2.0.12 in the dev tree). Then add a scanning gate: a bun audit --audit-level=high step in package-health.yml (which already owns "shape of what gets published" checks), and enable GitHub's Dependabot security updates plus actions/dependency-review-action on pull requests so a PR that introduces an advisory-carrying version fails before merge rather than after release.
Relationship to existing issues
Adjacent to #539, but a distinct mechanism. I verified every version pin claimed: bun.lock:392 fastify@5.10.0, :406 find-my-way@9.6.0, :390 fast-uri@3.1.0 and :694 fast-json-stringify/fast-uri@4.1.0, :660 ws@8.20.0, :116 @fastify/static@10.1.0, :120 @hono/node-server@2.0.9, :308 brace-expansion@5.0.5 — and package.json confirms fastify is one of only two runtime dependencies. I also confirmed the negative claim: grepping .github/ for audit|snyk|osv|codeql|scorecard|trivy|dependency-review returns only prose in the issue template and one comment in integration-brokers.yml — no scanning step exists. I could not independently confirm the advisory IDs (no network), so the GHSA list is taken on the finder's evidence. Relative to the corpus: #539 is a FEATURE request for the tooling class ("no dependency vulnerability scanning (osv-scanner / dependency-review-action / audit step)") and shares the second half of this finding. What #539 does not record — and what is separately actionable today — is that the lockfile is currently sitting on advisory-carrying versions in the runtime closure and that fixed releases already exist. So: file it, cross-referencing #539, scoped to the lockfile refresh plus a bun audit --audit-level=high gate in package-health.yml. Severity MEDIUM->LOW on the finding's own honest scoping: npm consumers do not receive bun.lock and resolve ^5.10.0 fresh, so the shipped package is unaffected; the exposed parties are this repo's CI, the Docker runners, and clone-and-run developers, and the remediation is a bun install away.
Verification status
Found in the second, independent whole-framework security re-audit of 2026-08-02 (v0.12.0) — a fresh pass run without reference to the first wave's findings, then triaged against the existing tracker and adjudicated by verifiers instructed to refute it.
Verifier note
I verified every lockfile pin claimed: bun.lock:392 fastify@5.10.0, :406 find-my-way@9.6.0, :390 fast-uri@3.1.0, :694 fast-json-stringify/fast-uri@4.1.0, :660 ws@8.20.0, :116 @fastify/static@10.1.0, :120 @hono/node-server@2.0.9, :308 brace-expansion@5.0.5. package.json confirms dependencies is exactly {fastify, ts-pattern}. I confirmed the negative claim by grep: audit|snyk|osv|codeql|scorecard|trivy|dependency-review across .github/ matches only prose in ISSUE_TEMPLATE/security_report.yml and one comment in integration-brokers.yml — none of the ten workflows queries an advisory database. I also spot-checked two advisories live rather than taking them on faith: GHSA-c96f-x56v-gq3h (find-my-way ≤9.6.0, HIGH/7.5, patched 9.7.0) and GHSA-v2hh-gcrm-f6hx (fast-uri ≥3.0.0 ≤3.1.3 and ≥4.0.0 ≤4.1.0, HIGH/7.5, patched 3.1.4/4.1.1). Both apply to the pinned versions. The finder's own scoping of consumer exposure is correct and I confirmed the mechanism: package.json files is ["dist/","README.md","CHANGELOG.md","LICENSE"], so bun.lock is not published and npm consumers resolve ^5.10.0 fresh. Corrected severity LOW → INFORMATIONAL, for three reasons established above: the one advisory with a concrete remote-exploit story is unreachable because no code path in src/ creates an HTTP/2 server; the Docker exposure claim collapses to a single Dockerfile once you check that the broker runners install without a lockfile; and no reachable trust decision in this codebase consumes a fast-uri-parsed authority (it enters only via ajv/fast-json-stringify internals). What genuinely remains is that the root lockfile is stale against published advisories and that nothing detects it — and the second half is already filed as #539. File this scoped to the mechanical remediation (bun update to refresh the pins) plus the bun audit --audit-level=high gate, cross-referencing #539, and without the HTTP/2 exploit narrative.
Correction applied: Three factual corrections, all reducing scope. (1) The headline exploit is NOT reachable. GHSA-c96f-x56v-gq3h requires Node's HTTP/2 server (I fetched the advisory: "improper handling of HTTP/2 method values that can resolve inherited object properties"). grep -rniE 'http2|http/2|allowHTTP1|createSecureServer' src/ returns ZERO hits, and FastifyBackend's constructor (src/http/backend/FastifyBackend.ts:49-50) defaults to { logger: false } — the framework never enables HTTP/2 on any backend. The claim "remotely triggerable by any client that can open an HTTP/2 connection to an actor-ts HTTP server" must be struck; only a consumer who explicitly passes { http2: true } into new FastifyBackend(...) is exposed. Also, the advisory's impact is an application crash (prototype pollution → CWE-1321), not "degrades the router into a CPU-bound state". (2) Exposure item (b) is wrong: the sixteen broker runners do NOT use bun.lock. Each Dockerfile.runner copies only tests/integration/brokers/package.json and runs bun install with no lockfile (verified in tests/integration/brokers/s3/Dockerfile.runner:20-22; grep -rn 'bun.lock' tests/ --include=Dockerfile* matches only tests/integration/Dockerfile.node:39). Those images therefore resolve fresh and get patched versions. Only one of the seventeen integration Dockerfiles is affected. (3) fast-uri's patched versions are 3.1.4 / 4.1.1 per GHSA-v2hh-gcrm-f6hx, not 4.1.2.
Component:
bun.lockSeverity (assessment): INFORMATIONAL
CWE: CWE-1104 (Use of Unmaintained/Vulnerable Third Party Components)
Related: #539
fastifyis one of only two hard runtime dependencies (package.json:238-241). The lockfile resolves it to 5.10.0, whose transitive router (find-my-way@9.6.0) and URI parser (fast-uri@3.1.0/4.1.0) are all at versions with published HIGH advisories. Nothing in the ten workflows queries an advisory database, so the lockfile can sit on known-vulnerable versions indefinitely with every gate green.Exploit walkthrough
Preconditions vary by advisory and by how the consumer resolves. Most direct:
find-my-wayis the router behindFastifyBackend, which is the framework's default HTTP backend. GHSA-c96f-x56v-gq3h is remotely triggerable by any client that can open an HTTP/2 connection to an actor-ts HTTP server — no authentication needed — and degrades the router into a CPU-bound state.fast-uri's host-confusion advisories matter wherever a parsed authority is used for a trust decision (origin checks, redirect validation, schema$refresolution inside ajv, which fastify uses for request-body validation).Honest scoping of who is actually exposed: consumers installing
actor-tsfrom npm do NOT receivebun.lock— they resolvefastify: ^5.10.0fresh and today would get 5.11.0 with patched transitives. The parties genuinely running the vulnerable versions are (a) this repository's own CI, including theprepublishOnlytest run inside the credential-bearing publish job, (b) every Docker integration runner (tests/integration/**/Dockerfile.runner, all of whichRUN bun install), (c) any consumer with a pinned or mirrored resolution, and (d) anyone who clones and runs the framework. The finding is therefore about the absence of a detection mechanism as much as the specific versions.Evidence —
bun.lockQueried the npm advisory bulk endpoint (
https://registry.npmjs.org/-/npm/v1/security/advisories/bulk, read-only POST) with the 294 distinct name@version pairs parsed out of bun.lock. Results inside the RUNTIME closure — computed by walking bun.lock fromdependencies= {fastify, ts-pattern} only (50 packages):Dev-tree only (not shipped to consumers, but present in every CI run and every
prepublishOnlytest run):Fixed versions all exist today: fastify 5.11.0, find-my-way 9.7.0, fast-uri 4.1.2, ws 8.21.1, @fastify/static 10.1.2, @hono/node-server 2.0.12 (queried live from the registry).
No scan step exists anywhere — grepping
.github/foraudit|snyk|osv|codeql|scorecard|trivy|dependency-reviewreturns only prose inISSUE_TEMPLATE/security_report.ymland a comment inintegration-brokers.yml.Note on
@fastify/static: it is a devDependency and NOT a peerDependency (package.json:117), and src/http/static/StaticFiles.ts:3 documents that the framework deliberately does not use it — so those two advisories are dev-surface only.Why the existing guard does not cover it
Dependabot runs daily against
/(dependabot.yml:6-12) with minor and patch grouped, sofastifybumps do get PR'd. But Dependabot version updates operate onpackage.jsonranges, and^5.10.0already admits 5.11.0 — and per the project's own documented experience (docs-checks.yml:41-46: "Dependabot bumpsdocs/package.jsonbut never regeneratesdocs/bun.lock"), the Bun lockfile is not maintained by that flow at all. Thelockfile-syncjob (docs-checks.yml:47-60) catches lockfile/manifest DRIFT, which is a different property from lockfile FRESHNESS against advisories: a lockfile can be perfectly in sync with its manifest and still pin four HIGH-severity transitive versions, which is exactly the current state. Nothing anywhere queries an advisory database.Suggested fix
Refresh the lockfile (
bun update fastify/bun installto pull find-my-way ≥9.7.0 and fast-uri ≥4.1.2, plus ws ≥8.21.1, @fastify/static ≥10.1.2, @hono/node-server ≥2.0.12 in the dev tree). Then add a scanning gate: abun audit --audit-level=highstep inpackage-health.yml(which already owns "shape of what gets published" checks), and enable GitHub's Dependabot security updates plusactions/dependency-review-actionon pull requests so a PR that introduces an advisory-carrying version fails before merge rather than after release.Relationship to existing issues
Adjacent to #539, but a distinct mechanism. I verified every version pin claimed: bun.lock:392 fastify@5.10.0, :406 find-my-way@9.6.0, :390 fast-uri@3.1.0 and :694 fast-json-stringify/fast-uri@4.1.0, :660 ws@8.20.0, :116 @fastify/static@10.1.0, :120 @hono/node-server@2.0.9, :308 brace-expansion@5.0.5 — and package.json confirms fastify is one of only two runtime dependencies. I also confirmed the negative claim: grepping .github/ for audit|snyk|osv|codeql|scorecard|trivy|dependency-review returns only prose in the issue template and one comment in integration-brokers.yml — no scanning step exists. I could not independently confirm the advisory IDs (no network), so the GHSA list is taken on the finder's evidence. Relative to the corpus: #539 is a FEATURE request for the tooling class ("no dependency vulnerability scanning (osv-scanner / dependency-review-action / audit step)") and shares the second half of this finding. What #539 does not record — and what is separately actionable today — is that the lockfile is currently sitting on advisory-carrying versions in the runtime closure and that fixed releases already exist. So: file it, cross-referencing #539, scoped to the lockfile refresh plus a
bun audit --audit-level=highgate in package-health.yml. Severity MEDIUM->LOW on the finding's own honest scoping: npm consumers do not receive bun.lock and resolve^5.10.0fresh, so the shipped package is unaffected; the exposed parties are this repo's CI, the Docker runners, and clone-and-run developers, and the remediation is abun installaway.Verification status
Found in the second, independent whole-framework security re-audit of 2026-08-02 (
v0.12.0) — a fresh pass run without reference to the first wave's findings, then triaged against the existing tracker and adjudicated by verifiers instructed to refute it.Verifier note
I verified every lockfile pin claimed: bun.lock:392
fastify@5.10.0, :406find-my-way@9.6.0, :390fast-uri@3.1.0, :694fast-json-stringify/fast-uri@4.1.0, :660ws@8.20.0, :116@fastify/static@10.1.0, :120@hono/node-server@2.0.9, :308brace-expansion@5.0.5. package.json confirmsdependenciesis exactly{fastify, ts-pattern}. I confirmed the negative claim by grep:audit|snyk|osv|codeql|scorecard|trivy|dependency-reviewacross.github/matches only prose in ISSUE_TEMPLATE/security_report.yml and one comment in integration-brokers.yml — none of the ten workflows queries an advisory database. I also spot-checked two advisories live rather than taking them on faith: GHSA-c96f-x56v-gq3h (find-my-way ≤9.6.0, HIGH/7.5, patched 9.7.0) and GHSA-v2hh-gcrm-f6hx (fast-uri ≥3.0.0 ≤3.1.3 and ≥4.0.0 ≤4.1.0, HIGH/7.5, patched 3.1.4/4.1.1). Both apply to the pinned versions. The finder's own scoping of consumer exposure is correct and I confirmed the mechanism:package.jsonfilesis["dist/","README.md","CHANGELOG.md","LICENSE"], so bun.lock is not published and npm consumers resolve^5.10.0fresh. Corrected severity LOW → INFORMATIONAL, for three reasons established above: the one advisory with a concrete remote-exploit story is unreachable because no code path insrc/creates an HTTP/2 server; the Docker exposure claim collapses to a single Dockerfile once you check that the broker runners install without a lockfile; and no reachable trust decision in this codebase consumes afast-uri-parsed authority (it enters only via ajv/fast-json-stringify internals). What genuinely remains is that the root lockfile is stale against published advisories and that nothing detects it — and the second half is already filed as #539. File this scoped to the mechanical remediation (bun updateto refresh the pins) plus thebun audit --audit-level=highgate, cross-referencing #539, and without the HTTP/2 exploit narrative.Correction applied: Three factual corrections, all reducing scope. (1) The headline exploit is NOT reachable. GHSA-c96f-x56v-gq3h requires Node's HTTP/2 server (I fetched the advisory: "improper handling of HTTP/2 method values that can resolve inherited object properties").
grep -rniE 'http2|http/2|allowHTTP1|createSecureServer' src/returns ZERO hits, andFastifyBackend's constructor (src/http/backend/FastifyBackend.ts:49-50) defaults to{ logger: false }— the framework never enables HTTP/2 on any backend. The claim "remotely triggerable by any client that can open an HTTP/2 connection to an actor-ts HTTP server" must be struck; only a consumer who explicitly passes{ http2: true }intonew FastifyBackend(...)is exposed. Also, the advisory's impact is an application crash (prototype pollution → CWE-1321), not "degrades the router into a CPU-bound state". (2) Exposure item (b) is wrong: the sixteen broker runners do NOT use bun.lock. EachDockerfile.runnercopies onlytests/integration/brokers/package.jsonand runsbun installwith no lockfile (verified in tests/integration/brokers/s3/Dockerfile.runner:20-22;grep -rn 'bun.lock' tests/ --include=Dockerfile*matches only tests/integration/Dockerfile.node:39). Those images therefore resolve fresh and get patched versions. Only one of the seventeen integration Dockerfiles is affected. (3) fast-uri's patched versions are 3.1.4 / 4.1.1 per GHSA-v2hh-gcrm-f6hx, not 4.1.2.