Update deps - #1135
Conversation
| return EncodedLookup[match]; | ||
| } | ||
|
|
||
| function decodeUtf8Text(text) { |
There was a problem hiding this comment.
decodeUtf8Text duplicates the ASCII optimization already handled by decodeText, adding redundant helper and call-site changes. Keep the existing decodeText calls and remove this duplicate path.
Details
✨ AI Reasoning
The change adds decodeUtf8Text and replaces two existing decodeText calls. However, decodeText now routes UTF-8 strings through decoders.utf8, whose isAscii check already returns ASCII input unchanged. Therefore the added helper provides no distinct behavior and unnecessarily expands the diff.
🔧 How do I fix it?
Limit the change to what's needed to achieve its intent. Avoid bundling unrelated reformatting or refactoring, and don't rewrite code that didn't need to change.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| if (RE_CHARSET.test(parsed[i][0])) { | ||
| charset = parsed[i][1].toLowerCase(); | ||
| break; | ||
| const contentType = header["content-type"][0]; |
There was a problem hiding this comment.
The content-type parsing branch reaches five nested control-flow levels across the fast-path check, parsed-parameter check, loop, and charset condition, making this logic difficult to follow.
Details
✨ AI Reasoning
The optimized content-type path adds an if/else around the existing parameter parsing logic. In the parsing branch, the code now combines several nested conditions with a loop and charset check, making the control flow harder to scan and maintain.
🔧 How do I fix it?
Keep nesting levels under 4. Extract complex logic into separate functions when indentation exceeds 4 levels.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| const value = | ||
| typeof headersValue === "string" | ||
| ? headersValue | ||
| : Array.isArray(headersValue) | ||
| ? headersValue.map((header) => header.toString("utf8")) | ||
| : headersValue.toString("utf8"); |
There was a problem hiding this comment.
The nested ternary used to convert headersValue creates a dense decision tree that is difficult to read.
Show fix
| const value = | |
| typeof headersValue === "string" | |
| ? headersValue | |
| : Array.isArray(headersValue) | |
| ? headersValue.map((header) => header.toString("utf8")) | |
| : headersValue.toString("utf8"); | |
| let value: string | string[]; | |
| if (typeof headersValue === "string") { | |
| value = headersValue; | |
| } else if (Array.isArray(headersValue)) { | |
| value = headersValue.map((header) => header.toString("utf8")); | |
| } else { | |
| value = headersValue.toString("utf8"); | |
| } |
Details
✨ AI Reasoning
The value expression distinguishes strings from arrays and then distinguishes all remaining values, creating a decision tree within a single assignment expression. The nested conditional makes the conversion logic harder to scan and understand.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| const value = | ||
| typeof headersValue === "string" | ||
| ? headersValue | ||
| : Array.isArray(headersValue) | ||
| ? headersValue.map((header) => header.toString("utf8")) | ||
| : headersValue.toString("utf8"); |
There was a problem hiding this comment.
The nested ternary used to derive value compresses multiple type checks and conversions into one decision chain, making this header parsing logic harder to read.
Show fix
| const value = | |
| typeof headersValue === "string" | |
| ? headersValue | |
| : Array.isArray(headersValue) | |
| ? headersValue.map((header) => header.toString("utf8")) | |
| : headersValue.toString("utf8"); | |
| let value: string | string[]; | |
| if (typeof headersValue === "string") { | |
| value = headersValue; | |
| } else if (Array.isArray(headersValue)) { | |
| value = headersValue.map((header) => header.toString("utf8")); | |
| } else { | |
| value = headersValue.toString("utf8"); | |
| } |
Details
✨ AI Reasoning
The value assignment uses a ternary whose alternate branch contains another ternary. Readers must evaluate multiple type checks and conversion paths within one expression, making the header value handling harder to scan and understand.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| this.tail = data.length >= 3 | ||
| ? data.toString('binary', data.length - 3) | ||
| : (tail + data.toString('binary')).slice(-3) |
There was a problem hiding this comment.
🟡 Medium - Multipart headers are dropped when the CRLFCRLF delimiter crosses a write boundary
When a header chunk ends in the first \r of the terminating \r\n\r\n, push() stores that byte in this.buffer; the next chunk can satisfy the cross-chunk match without appending/removing the already-buffered byte. _parseHeader() then treats the trailing bare \r as invalid and returns before emitting the final header, so Dicer sees no content-disposition and multipart.js skips the part. Incoming request chunks are attacker-controlled in size, so a client can make valid multipart fields/files invisible to this firewall's body inspection while the original body is still replayed to the application.
Show fix
Keep delimiter-prefix bytes out of the accumulated header buffer, or remove the bytes that belong to a cross-chunk \r\n\r\n match before _finish() parses the header. Add a regression test that writes a valid multipart header with the final header delimiter split after each of its first three bytes, and verify that the field/file event is still emitted.
More info - Reply on this comment to give feedback or ignore the issue.
| HeaderParser.prototype.push = function (data) { | ||
| if (!Buffer.isBuffer(data)) { data = Buffer.from(data, 'binary') } |
There was a problem hiding this comment.
🔵 Low - HeaderParser emits duplicate headers after it has finished
_finish() marks the parser as finished, but push() no longer checks that state and continues searching for later \r\n\r\n sequences. In Dicer's documented headerFirst mode, subsequent streamed preamble data is still forwarded to push(), so an attacker can cause a second header event for the same preamble and leave consumers with inconsistent header/boundary state. This regresses the exported Dicer parser contract and can lead to duplicate processing or parser errors for users of that mode.
Show fix
Return immediately from HeaderParser.push() when this.finished is already true, preserving the previous behavior, and add a headerFirst regression test that writes a second header block after the first terminator and asserts only one header event is emitted.
More info - Reply on this comment to give feedback or ignore the issue.
| } | ||
|
|
||
| export interface Busboy extends Writable { | ||
| export interface BusboyInstance extends Writable { |
There was a problem hiding this comment.
🔵 Low - Renaming the exported Busboy instance type breaks the TypeScript build
The declaration file now exports BusboyInstance instead of the previously exported Busboy interface, while readBodyStream.ts still uses let busboy: Busboy | undefined with the imported Busboy value. Because package.json now resolves types through this file, the project reports TS2749 (Busboy refers to a value, but is being used as a type), and downstream consumers using the formerly public Busboy type also fail to compile. This is an API-breaking type regression in a patch-level dependency update.
Show fix
Preserve the existing public type name by re-exporting Busboy as the instance interface (or a type alias to BusboyInstance) and keep the constructor's return type compatible; update the internal annotation or add a type-level regression test so the package and firewall TypeScript builds compile against the new types.
More info - Reply on this comment to give feedback or ignore the issue.
| if (str.indexOf(";") === -1) { | ||
| return [decodeUtf8Text(str)]; | ||
| } |
There was a problem hiding this comment.
🔵 Low - Whitespace-only Content-Type values are no longer normalized before file detection
The new semicolon-free fast path returns the value unchanged, whereas the previous parser discarded spaces and tabs outside quotes. A multipart part with Content-Type: application/octet-stream or a trailing space, plus Content-Disposition: form-data; name=blob without a filename, therefore gets a whitespace-polluted contype and fails the exact default octet-stream file check. This changes the part from a file stream to a field and applies different limits and event handling for valid headers containing optional whitespace.
Show fix
Normalize optional spaces and tabs in the semicolon-free Content-Type path before returning it, or keep using the existing state-machine parser for whitespace-containing values; add tests for leading and trailing OWS around application/octet-stream and assert the default file classification.
More info - Reply on this comment to give feedback or ignore the issue.
| "lint": "eslint", | ||
| "lint:fix": "eslint --fix", |
There was a problem hiding this comment.
🔵 Low - The package lint script now fails because ESLint has no configuration
The package script invokes bare eslint, but this update removes the Standard-based command without adding an ESLint 9 flat config or legacy configuration. Running the package's documented lint command therefore exits with ESLint's missing-configuration error instead of checking the source, so CI or maintainers cannot run the advertised lint step successfully.
Show fix
Add an eslint.config.js/mjs/cjs that configures the intended rules and ignores, or keep the prior Standard-based lint command; run the package lint script in CI to ensure it exits successfully.
More info - Reply on this comment to give feedback or ignore the issue.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
No description provided.