Skip to content

Bump @fastify/busboy from 3.2.0 to 3.2.4 [SECURITY] - #1129

Open
superbot-helper wants to merge 1 commit into
marklogic:masterfrom
superbot-helper:security/bump-fastify-busboy-3.2.4
Open

superbot-helper wants to merge 1 commit into
marklogic:masterfrom
superbot-helper:security/bump-fastify-busboy-3.2.4

Conversation

@superbot-helper

Copy link
Copy Markdown

@fastify/busboy 3.2.0 is pinned exactly in package.json and resolved to 3.2.0 in package-lock.json. Three published advisories cover that version. This pull request moves the pin and the one lock entry to 3.2.4.

Two files change, because the dependency is pinned exactly: package.json "@fastify/busboy": "3.2.0" becomes "3.2.4" (same exact-pin form, no range widening), and in package-lock.json the node_modules/@fastify/busboy entry plus the lock's own root "" dependency spec. git diff --stat is 2 files, 5 insertions, 5 deletions; one lock entry moves (the root "" key excluded by construction). A lock-only edit is not installable here: npm ci refuses it with EUSAGE: Invalid: lock file's @fastify/busboy@3.2.4 does not satisfy @fastify/busboy@3.2.0, so the manifest moves with it.

The advisories

advisory what fixed in
GHSA-xjh9-v7x6-24jw / CVE-2026-19484 (HIGH) DoS: a boundary token of exactly 252 bytes makes the streaming-search needle 256 bytes and the occurrence-table entry wraps to zero, so the Boyer-Moore loop never advances. Range >= 3.1.0, < 3.2.1 3.2.1
GHSA-x8mw-p69m-v3mx / CVE-2026-19481 (HIGH) DoS: a part header named __proto__ or constructor resolves to an inherited non-array value and the parser throws TypeError: this.header[h].push is not a function. Range >= 1.0.0, < 3.2.1 3.2.1
GHSA-gxm5-99cw-xjw9 / CVE-2026-74866 (MODERATE) CRLF injection through a Content-Disposition filename. Range < 3.2.2 3.2.2

OSV returns three advisories for 3.2.0, one for 3.2.1, and none for 3.2.2, 3.2.3 and 3.2.4.

Where this parser sits in this library

This is a client library, so the multipart body it parses is an HTTP response from the MarkLogic REST server. The package is imported directly, not through multipart-stream:

  • lib/responder.js:7 — const Dicer = require('@fastify/busboy/deps/dicer/lib/Dicer'); — the only import of @fastify/busboy in the tree.
  • lib/responder.js:48 selects the multipart dispatcher when the response Content-Type starts with multipart/mixed; :92 builds MultipartDispatcher; :617 constructs new Dicer({boundary}); :626 pipes the response into it. The same pattern repeats for the stream modes at :688 and :878.
  • lib/documents.js:619 exposes documents.read(); :703 asks for Accept: multipart/mixed when more than one URI is read, and lib/requester.js:260-261 hands the response to responder.responseDispatcher.
  • multipart-stream (lib/requester.js:8) only builds request bodies (:487, :500); its dependencies are inherits, is-stream and sandwich-stream, and it never loads busboy. The vulnerable parser is reached through the direct deep import of the vendored Dicer.

What was measured

The library's own entry point (lib/marklogic.js, the package main) was required by a child process and pointed at a local mock REST server that answers GET /v1/documents with one multipart/mixed body. documents.read(['/doc1.json','/doc2.json']).result() was driven once per arm, one process per arm. Every response was HTTP 200; the rows differ in whether the client's parse resolves, rejects, or never returns. @fastify/busboy loads at require time, before any request — the Module._load hook and a positive/negative control are in evidence/gates/.

arm 3.2.0 3.2.4
control: two well-formed JSON parts resolved, 209 ms resolved, 127 ms
part headers __proto__: polluted and constructor: also rejected, 100 ms — TypeError: this.header[h].push is not a function at deps/dicer/lib/HeaderParser.js:95:20 resolved, 106 ms
filename="a\rb\nc.json" (raw CR then LF) resolved, 195 ms resolved, 86 ms
boundary token 252 x A, false delimiter prefix cut at its first B: 20,625 bytes, 150 ms pause, 4,262 bytes no return — killed at the 5,000 ms deadline, 4.62 s CPU, event-loop heartbeat stops at 202.47 ms resolved, 230 ms
the identical 24,887 bytes in one server write resolved, 208 ms resolved, 70 ms

A parser-only probe of the same bytes (Dicer, no HTTP) reproduces the two defects at the library level: __proto__ throws on write in 0.75 ms on 3.2.0 and finishes in 1.18 ms on 3.2.4; the fragmented 252-byte boundary never returns on 3.2.0 (killed at 5,000 ms) and finishes in 152.24 ms on 3.2.4; the one-write variant finishes in 2.57 ms and 1.75 ms; the control and CRLF arms finish on both.

The CRLF arm is the one where the client's outcome does not change: this path uses only Content-Type, and Dicer's header event differs (3.2.0 yields a content-disposition value containing byte 13 then byte 10; 3.2.4 drops that malformed header line) without changing the resolved result. The 3.2.2 fix in busboy's own multipart Content-Disposition handling is not on this path, and this pull request does not claim an injection consequence here.

Limits

  • The trigger is the response side: the boundary token and its fragmentation are chosen by the server or an intermediary, not by the application. The packet demonstrates the client-side consequence on a mock server it controls, not a compromise of any deployed MarkLogic instance.
  • No file is written anywhere in this path; the observable is the documents.read() result promise.
  • The repository's .npmrc sets min-release-age=14 and 3.2.4 was published 2026-10-22, 9 days before this patch, so the lock was regenerated with --min-release-age=0; a plain npm install --package-lock-only refuses with ETARGET ... with a date before 10/17/2026. npm ci does not resolve, and installs the locked 3.2.4 with exit 0. The .npmrc is unchanged.
  • npm ci was run on both trees: exit 0 on the base (busboy 3.2.0) and exit 0 on this patch (3.2.4), 433 packages each.
  • A boundary token of 253 bytes or more throws The needle cannot have a length bigger than 256 on every version, including 3.2.4; that constructor guard is not a defect and is not claimed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the @fastify/busboy 3.2.4 dependency update.

No open issues 🎉

What changed in this PR

Updates @fastify/busboy from 3.2.0 to 3.2.4 to address security advisories affecting the multipart parser used for MarkLogic HTTP responses.

Changes:

  • Preserves exact dependency pinning while upgrading to 3.2.4.
  • Synchronizes the lockfile’s root dependency, resolved package URL, and integrity hash with the new version.
File Description
package.json Updates the exact @fastify/busboy pin to 3.2.4.
package-lock.json Aligns the dependency specification and locked package metadata with 3.2.4.

Review effort: Balanced

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