Repository navigation
Bump @fastify/busboy from 3.2.0 to 3.2.4 in package-lock.json [SECURITY] - #1877
Open
superbot-helper wants to merge 1 commit into
Open
superbot-helper wants to merge 1 commit into
superbot-helper wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
package.jsondeclares"@fastify/busboy": "^3.2.0"(package.json:62) andpackage-lock.jsonresolves the single installed copy,node_modules/@fastify/busboy, to 3.2.0, which carries three published advisories. This pull request moves that one lock entry to 3.2.4, the current registrylatest.package.jsonis not touched:^3.2.0already admits3.2.4, so the change is installable as a lock-only edit and the manifest stays byte-identical. There is exactly one lock entry that declares the package (the lock's own root""entry, which mirrorspackage.json) and exactly one installed copy; there is no nested or second copy under anynode_modules/.../node_modulespath.npm ciexits 0 on both the base pair and this patch's pair.The advisories
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)new Uint8Array(256).fill(256), which truncates every entry to 0, so a near-match split across two writes never advancespos += this._occ[ch]and the event loop spins>= 3.1.0, < 3.2.1AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)__proto__orconstructorresolves to an inherited non-array and the parser throwsTypeError: this.header[h].push is not a function>= 1.0.0, < 3.2.1AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:NContent-Dispositionfilename/nameparameter is retained verbatim and delivered to the application< 3.2.2OSV returns these three for
3.2.0, one (GHSA-gxm5-99cw-xjw9) for3.2.1, and none for3.2.2,3.2.3or3.2.4.Why this parser is on an executed path here
lib/handlers/post.mjs:1—import Busboy from '@fastify/busboy'(a static ESM import, so the package is loaded when the process starts, not per request).lib/ldp-middleware.mjs:5imports that handler andlib/ldp-middleware.mjs:25registers it:router.post('/*', allow('Append'), post).lib/create-app.mjs:137mounts the router:app.use('/', LdpMiddleware(corsSettings, argv.prep));lib/create-server.mjs:13builds the app and:21mounts it;bin/solid:2→bin/lib/cli.mjs:20→bin/lib/start.mjs:99start it.lib/handlers/post.mjs:45testsreq.is('multipart/form-data')and:51multi()constructs the parser at:54(new Busboy({ headers: req.headers })) and feeds it at:76(req.pipe(busboy)). Each file event is written into the container at:60(ldp.put(putUrl, file, mimetype)).webidis off:lib/handlers/allow.mjs:7-9returnsnext()immediately whenldp.webidis false. The measurements below ran the server withSOLID_WEBID=falseon127.0.0.1, and every request carried noAuthorization, cookie or token.What was measured
The program was started as
node bin/solid start --port <port> --root <dir> --no-livewithSOLID_WEBID=false(plain HTTP;lib/create-server.mjs:34-36only creates a TLS server when--ssl-key/--ssl-certare given), once from a tree installed bynpm ciagainst the base lock (@fastify/busboy3.2.0) and once from a tree installed against this patch's lock (3.2.4). Each arm is one raw-socketPOST /withContent-Type: multipart/form-data, followed by aGET /liveness probe on the same process. Times are from the client: TTFB where a response arrived, total where the client gave up.A
Module._loadhook preloaded into the server process logged the package load at startup —[busboy-load] request=…/@fastify/busboy/lib/main.js … version=3.2.0— so the parser is loaded by the server itself, not by the harness. A positive control (node --require hook.cjs control-esm.mjs) logs the same line; a negative control (requiring an unrelated module) logs none.POST /, one part)filename="control.txt", 152-byte bodycontrol.txt(15 bytes) stored; process alivecontrol.txt(15 bytes) stored; process alive__proto__: pollutedandconstructor: alsoError receiving the file; the server log carriessolid:post Error receiving the file: this.header[h].push is not a function; no file storedproto.txt(15 bytes) stored — the part parsed and reachedldp.putfilename="a\rb\nc.txt"(raw CR then raw LF inside the quotes)a\rb\nc.txtwith the CR and LF inside the name (15 bytes)A, one client write, 24,866-byte bodyfrag.txt(24,256 bytes) storedfrag.txt(24,256 bytes) storedGET /on the same process then timed out at 4,001 ms; the process's CPU time went 0:00.42 → 0:12.21 while serving nothing;frag.txtwas left at 20,000 of its 24,256 bytesfrag.txt(24,256 bytes) stored; the follow-upGET /returned 200Parser level, against the packages each
npm ciinstalled, byte-identical payloads, one child process per row, killed at 8 s:__proto__/constructorpart headersTypeError: this.header[h].push is not a functionatdeps/dicer/lib/HeaderParser.js:95(uncaught, child exits 1)fileeventproto.txtfilename="a\rb\nc.txt"fileevent with filename bytes97,13,98,10,99,46,116,120,116fileevent (part skipped)The last two rows are the point: a 252-byte boundary alone is not a denial of service. The trigger is the near-match split across two writes. In this endpoint the split is the client's — the request body arrives over the socket in whatever chunks the client writes — so a client that writes the body in two pieces at a chosen offset gets the spin deterministically; the same bytes in one write complete on both versions in under 2 ms. The payload places
\r\n--+ 250 ×A+BBin the body so that the first write ends after 254 bytes of the 256-byte needle and the second begins withB, a byte the 3.2.0 occurrence table has no entry for;deps/streamsearch/sbmh.js:129(pos += this._occ[ch]) then advances by zero. 3.2.4 builds that table asnew Uint16Array(256)(sbmh.js:56), so 256 no longer wraps to 0.Limits
The needle cannot have a length bigger than 256on every version including 3.2.4; that is a constructor guard, not one of the advisories, and nothing here depends on it.__proto__row's 500 is the handler's own envelope (lib/handlers/post.mjs:65-67); the parser'sTypeErrormessage appears in the server log and, uncaught, in the parser-level probe. The status is the application's, the exception is the parser's.POST /against the storage root. Other container paths are the same handler (router.post('/*', …),lib/ldp-middleware.mjs:25); no other path was driven.SOLID_WEBID=false. With WebID on,allow.mjsperforms an ACL check before the handler; that path was not exercised, and the parser is reached either way once the request is authorized.npm testrunseslint, a Turtle validator and the fullc8mocha suite against live servers, and it takes far longer than a dependency bump warrants.npm ciand the running-program arms are the gates that were run.@fastify/busboypast 3.2.0 (916 PRs screened, every changed-file list read, every lock-touching diff classified, the six too-large diffs read from their head locks). The only PR that names the package is update busboy to @fastify/busboy #1647, merged 2021-12-27, which migratedbusboy@0.3.1to@fastify/busboy@1.0.0.Verification
npm ci --no-audit --no-fundon a copy of the base tree: exit 0, 1,315 packages, installs@fastify/busboy3.2.0. The same command on the same tree with this patch'spackage-lock.json: exit 0, 1,315 packages, installs 3.2.4.package.jsonis byte-identical in both trees (cmpexit 0).node_modules/@fastify/busboy(version,resolved,integrity), +3/−3 lines. The lock's root""entry and every other entry are byte-identical; the entry count stays 1,326.@fastify/busboy@3.2.4declares nodependenciesand noengines, so the entry's absentdependenciesblock is correct for the new version.patch.diffapplied to the base lock reproduces the shipped lock byte for byte (sha256d825386a…), and that file is the blob in the commit this branch carries..github/dependabot.yml. It has arenovate.json(extends: config:base), but the newest Renovate pull request is Update dependency snyk to v1.427.1 #1516 from 2020-11-12.