Skip to content

Update dependency form-data@<2.5.4 to v4 [SECURITY]#28616

Open
tryghost-renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-form-data-2.5.4-vulnerability
Open

Update dependency form-data@<2.5.4 to v4 [SECURITY]#28616
tryghost-renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-form-data-2.5.4-vulnerability

Conversation

@tryghost-renovate

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
form-data@<2.5.4 ^2.5.4^4.0.0 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


form-data: CRLF injection in form-data via unescaped multipart field names and filenames

CVE-2026-12143 / GHSA-hmw2-7cc7-3qxx

More information

Details

Summary

form-data builds multipart/form-data request bodies. Through v4.0.5, the field name passed to FormData#append and the filename option are concatenated directly into the Content-Disposition header with no escaping of CR (\r), LF (\n), or ". An application that uses untrusted input as a field name or filename therefore lets an attacker terminate the header line and either inject additional headers or smuggle whole additional multipart parts into the request the application forwards to a backend.

This is CWE-93 (CRLF injection). It is a divergence from how browsers and the WHATWG HTML spec serialize form-data (they escape these characters), so the fix is to match that behavior. Severity is conditional: it depends on the consuming application passing attacker-controlled data as a field name or filename. Applications that only use fixed/trusted field names are not affected.

Details

In lib/form_data.js, _multiPartHeader builds the part header as:

'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || [])

and _getContentDisposition builds filename="' + filename + '"'. Neither escapes control characters, so a \r\n in field/filename ends the header line. The same applies to ", which can break out of the quoted parameter.

Proof of concept
const FormData = require('form-data');
const form = new FormData();
form.append('email"\r\nX-Injected: true\r\nfake="', 'user@example.com');
console.log(form.getBuffer().toString());

Before the fix this emits an injected X-Injected: true header line. A field name that also includes --<boundary> sequences can introduce additional parts (e.g. an extra name="is_admin" field), which a downstream parser accepts as legitimate.

Impact

For an application that uses untrusted field names/filenames:

  • Field injection / override (integrity). Inject or override fields the backend trusts (e.g. is_admin, role) — the primary demonstrated impact.
  • Header injection into the generated multipart part.

Claims of guaranteed privilege escalation, authentication bypass, high confidentiality impact, and availability impact are application-dependent downstream consequences, not properties of form-data itself, and are not demonstrated by the PoC.

Severity

The demonstrated, library-attributable impact is integrity (field/header injection); there is no demonstrated confidentiality disclosure or availability impact in form-data itself, and exploitation requires the consuming app to feed untrusted data into field names/filenames. A Moderate (≈5.3, I:L) rating is also defensible given that precondition.

Patch

Fixed in 4.0.6, 3.0.5, and 2.5.6. Users on older 0.x/1.x/2.x releases should upgrade to 2.5.6 or later.

The fix escapes \r, \n, and " as %0D, %0A, and %22 in field names and filenames, matching the WHATWG HTML multipart/form-data encoding algorithm that browsers implement. This neutralizes the injection while leaving ordinary field names (including name[0], dotted, and unicode names) unchanged.

Workaround

Until upgrading, validate or reject field names/filenames that contain control characters before calling append:

if (/[\r\n]/.test(field)) { throw new Error('invalid field name'); }
Credit

Reported by yueyueL.

Severity

  • CVSS Score: 8.7 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

form-data/form-data (form-data@<2.5.4)

v4.0.6

Compare Source

Commits
  • [Fix] escape CR, LF, and " in field names and filenames 8dff42c
  • [Dev Deps] update @ljharb/eslint-config, auto-changelog, tape f31d21e
  • [Deps] update hasown, mime-types 92ae0eb
  • [Dev Deps] update js-randomness-predictor 67b0f65

v4.0.5

Compare Source

Commits
  • [Tests] Switch to newer v8 prediction library; enable node 24 testing 16e0076
  • [Dev Deps] update @ljharb/eslint-config, eslint 5822467
  • [Fix] set Symbol.toStringTag in the proper place 76d0dee

v4.0.4

Compare Source

Commits
  • [meta] add auto-changelog 811f682
  • [Tests] handle predict-v8-randomness failures in node < 17 and node > 23 1d11a76
  • [Fix] Switch to using crypto random for boundary values 3d17230
  • [Tests] fix linting errors 5e34080
  • [meta] actually ensure the readme backup isn’t published 316c82b
  • [Dev Deps] update @ljharb/eslint-config 58c25d7
  • [meta] fix readme capitalization 2300ca1

v4.0.3

Compare Source

Fixed
  • [Fix] append: avoid a crash on nullish values #577
Commits
  • [eslint] use a shared config 426ba9a
  • [eslint] fix some spacing issues 2094191
  • [Refactor] use hasown 81ab41b
  • [Fix] validate boundary type in setBoundary() method 8d8e469
  • [Tests] add tests to check the behavior of getBoundary with non-strings 837b8a1
  • [Dev Deps] remove unused deps 870e4e6
  • [meta] remove local commit hooks e6e83cc
  • [Dev Deps] update eslint 4066fd6
  • [meta] fix scripts to use prepublishOnly c4bbb13

v4.0.2

Compare Source

Merged
  • [Fix] set Symbol.toStringTag when available #573
  • [Fix] set Symbol.toStringTag when available #573
  • fix (npmignore): ignore temporary build files #532
  • fix (npmignore): ignore temporary build files #532
Fixed
  • [Fix] set Symbol.toStringTag when available (#​573) #396
  • [Fix] set Symbol.toStringTag when available (#​573) #396
  • [Fix] set Symbol.toStringTag when available #396
Commits
  • Merge tags v2.5.3 and v3.0.3 92613b9
  • [Tests] migrate from travis to GHA 806eda7
  • [Tests] migrate from travis to GHA 8fdb3bc
  • [Refactor] use Object.prototype.hasOwnProperty.call 7fecefe
  • [Refactor] use Object.prototype.hasOwnProperty.call 6e682d4
  • [Refactor] use Object.prototype.hasOwnProperty.call df3c1e6
  • [Dev Deps] update @types/node, browserify, coveralls, cross-spawn, eslint, formidable, in-publish, pkgfiles, pre-commit, puppeteer, request, tape, typescript 8261fcb
  • [Dev Deps] update @types/node, browserify, coveralls, cross-spawn, eslint, formidable, in-publish, pkgfiles, pre-commit, puppeteer, request, tape, typescript fb66cb7
  • [Dev Deps] update @types/node, browserify, coveralls, eslint, formidable, in-publish, phantomjs-prebuilt, pkgfiles, pre-commit, request, tape, typescript 819f6b7
  • [eslint] clean up ignores 3217b3d
  • [eslint] clean up ignores 3a9d480
  • [Fix] Buffer.from and Buffer.alloc require node 4+ c499f76
  • Only apps should have lockfiles b82f590
  • Only apps should have lockfiles b170ee2
  • [Deps] update combined-stream, mime-types 6b1ca1d
  • [Dev Deps] pin request which via tough-cookie ^2.4 depends on psl e5df7f2
  • [Deps] update mime-types 5a5bafe
  • Bumped version 2.5.3 9457283
  • [Dev Deps] pin request which via tough-cookie ^2.4 depends on psl 9dbe192
  • Merge tags v2.5.2 and v3.0.2 d53265d
  • Bumped version 2.5.2 7020dd4
  • [Dev Deps] downgrade cross-spawn 3fc1a9b
  • fix: move util.isArray to Array.isArray (#​564) edb555a
  • fix: move util.isArray to Array.isArray (#​564) 10418d1

v4.0.1

Compare Source

Commits
  • [Tests] migrate from travis to GHA 757b4e3
  • [eslint] clean up ignores e8f0d80
  • fix (npmignore): ignore temporary build files 335ad19
  • fix: move util.isArray to Array.isArray 440d3be

v4.0.0

Compare Source

Merged
  • Handle custom stream #382
Commits

v3.0.5

Compare Source

Commits
  • [Fix] escape CR, LF, and " in field names and filenames 8777e67
  • [Dev Deps] update @ljharb/eslint-config, auto-changelog, eslint, tape 27c61a5
  • [Deps] update hasown 6a8a1c6

v3.0.4

Compare Source

Fixed
  • [Fix] append: avoid a crash on nullish values #577
Commits
  • [eslint] update linting config f5e7eb0
  • [meta] add auto-changelog d2eb290
  • [Tests] handle predict-v8-randomness failures in node < 17 and node > 23 e8c574c
  • [Fix] Switch to using crypto random for boundary values c6ced61
  • [Refactor] use hasown 1a78b5d
  • [Fix] validate boundary type in setBoundary() method 70bbaa0
  • [Tests] add tests to check the behavior of getBoundary with non-strings b22a64e
  • [meta] actually ensure the readme backup isn’t published 0150851
  • [meta] remove local commit hooks fc42bb9
  • [Dev Deps] remove unused deps a14d09e
  • [meta] fix scripts to use prepublishOnly 11d9f73
  • [meta] fix readme capitalization fc38b48

v3.0.3

Compare Source

Merged
  • [Fix] set Symbol.toStringTag when available #573
  • [Fix] set Symbol.toStringTag when available #573
  • fix (npmignore): ignore temporary build files #532
  • fix (npmignore): ignore temporary build files #532
Fixed
  • [Fix] set Symbol.toStringTag when available (#​573) #396
  • [Fix] set Symbol.toStringTag when available (#​573) #396
  • [Fix] set Symbol.toStringTag when available #396
Commits
  • Merge tags v2.5.3 and v3.0.3 92613b9
  • [Tests] migrate from travis to GHA 806eda7
  • [Tests] migrate from travis to GHA 8fdb3bc
  • [Refactor] use Object.prototype.hasOwnProperty.call 7fecefe
  • [Refactor] use Object.prototype.hasOwnProperty.call 6e682d4
  • [Refactor] use Object.prototype.hasOwnProperty.call df3c1e6
  • [Dev Deps] update @types/node, browserify, coveralls, cross-spawn, eslint, formidable, in-publish, pkgfiles, pre-commit, puppeteer, request, tape, typescript 8261fcb
  • [Dev Deps] update @types/node, browserify, coveralls, cross-spawn, eslint, formidable, in-publish, pkgfiles, pre-commit, puppeteer, request, tape, typescript fb66cb7
  • [Dev Deps] update @types/node, browserify, coveralls, eslint, formidable, in-publish, phantomjs-prebuilt, pkgfiles, pre-commit, request, tape, typescript 819f6b7
  • [eslint] clean up ignores 3217b3d
  • [eslint] clean up ignores 3a9d480
  • [Fix] Buffer.from and Buffer.alloc require node 4+ c499f76
  • Only apps should have lockfiles b82f590
  • Only apps should have lockfiles b170ee2
  • [Deps] update combined-stream, mime-types 6b1ca1d
  • [Dev Deps] pin request which via tough-cookie ^2.4 depends on psl e5df7f2
  • [Deps] update mime-types 5a5bafe
  • Bumped version 2.5.3 9457283
  • [Dev Deps] pin request which via tough-cookie ^2.4 depends on psl 9dbe192
  • Merge tags v2.5.2 and v3.0.2 d53265d
  • Bumped version 2.5.2 7020dd4
  • [Dev Deps] downgrade cross-spawn 3fc1a9b
  • fix: move util.isArray to Array.isArray (#​564) edb555a
  • fix: move util.isArray to Array.isArray (#​564) 10418d1

v3.0.2

Compare Source

Merged
  • [Fix] set Symbol.toStringTag when available #573
  • [Fix] set Symbol.toStringTag when available #573
  • fix (npmignore): ignore temporary build files #532
  • fix (npmignore): ignore temporary build files #532
Fixed
  • [Fix] set Symbol.toStringTag when available (#​573) #396
  • [Fix] set Symbol.toStringTag when available (#​573) #396
  • [Fix] set Symbol.toStringTag when available #396
Commits
  • Merge tags v2.5.3 and v3.0.3 92613b9
  • [Tests] migrate from travis to GHA 806eda7
  • [Tests] migrate from travis to GHA 8fdb3bc
  • [Refactor] use Object.prototype.hasOwnProperty.call 7fecefe
  • [Refactor] use Object.prototype.hasOwnProperty.call 6e682d4
  • [Refactor] use Object.prototype.hasOwnProperty.call df3c1e6
  • [Dev Deps] update @types/node, browserify, coveralls, cross-spawn, eslint, formidable, in-publish, pkgfiles, pre-commit, puppeteer, request, tape, typescript 8261fcb
  • [Dev Deps] update @types/node, browserify, coveralls, cross-spawn, eslint, formidable, in-publish, pkgfiles, pre-commit, puppeteer, request, tape, typescript fb66cb7
  • [Dev Deps] update @types/node, browserify, coveralls, eslint, formidable, in-publish, phantomjs-prebuilt, pkgfiles, pre-commit, request, tape, typescript 819f6b7
  • [eslint] clean up ignores 3217b3d
  • [eslint] clean up ignores 3a9d480
  • [Fix] Buffer.from and Buffer.alloc require node 4+ c499f76
  • Only apps should have lockfiles b82f590
  • Only apps should have lockfiles b170ee2
  • [Deps] update combined-stream, mime-types 6b1ca1d
  • [Dev Deps] pin request which via tough-cookie ^2.4 depends on psl e5df7f2
  • [Deps] update mime-types 5a5bafe
  • Bumped version 2.5.3 9457283
  • [Dev Deps] pin request which via tough-cookie ^2.4 depends on psl 9dbe192
  • Merge tags v2.5.2 and v3.0.2 d53265d
  • Bumped version 2.5.2 7020dd4
  • [Dev Deps] downgrade cross-spawn 3fc1a9b
  • fix: move util.isArray to Array.isArray (#​564) edb555a
  • fix: move util.isArray to Array.isArray (#​564) 10418d1

v3.0.1

Compare Source

Merged
  • Fix typo: ads -> adds #451
Commits
  • feat: add setBoundary method 55d90ce

v3.0.0

Compare Source

Merged
  • Update Readme.md #449
  • Update package.json #448
  • fix memory leak #447
  • form-data: Replaced PhantomJS Dependency #442
  • Fix constructor options in Typescript definitions #446
  • Fix the getHeaders method signatures #434
  • Update combined-stream (fixes #​422) #424
Fixed
  • Merge pull request #​424 from botgram/update-combined-stream #422
  • Update combined-stream (fixes #​422) #422
Commits
  • Add readable stream options to constructor type 80c8f74
  • Fixed: getHeaders method signatures f4ca7f8
  • Pass options to constructor if not used with new 4bde68e
  • Make userHeaders optional 2b4e478

Configuration

📅 Schedule: (in timezone Etc/UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • Only on Sunday and Saturday (* * * * 0,6)
    • Between 11:00 PM and 11:59 PM, Monday through Friday (* 23 * * 1-5)
    • Between 12:00 AM and 04:59 AM, Monday through Saturday (* 0-4 * * 1-6)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate.

@tryghost-renovate tryghost-renovate Bot added dependencies Pull requests that update a dependency file security labels Jun 16, 2026
@tryghost-renovate

tryghost-renovate Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ Artifact update problem

Renovate failed to update an artifact related to this branch. You probably do not want to merge this PR as-is.

♻ Renovate will retry this branch, including artifacts, only when one of the following happens:

  • any of the package files in this branch needs updating, or
  • the branch becomes conflicted, or
  • you click the rebase/retry checkbox if found above, or
  • you rename this PR's title to start with "rebase!" to trigger it manually

The artifact failure details are included below:

File name: pnpm-lock.yaml

<--- Last few GCs --->

[1593:0x36728000]    40352 ms: Mark-Compact (reduce) 1027.3 (1043.0) -> 1024.7 (1039.3) MB, pooled: 0 MB, 330.52 / 0.03 ms  (+ 125.7 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 486 ms) (average mu = 0.274, cu

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

 1: 0xe46bbe node::OOMErrorHandler(char const*, v8::OOMDetails const&) [/opt/containerbase/tools/node/22.22.3/bin/node]
 2: 0x1243640 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [/opt/containerbase/tools/node/22.22.3/bin/node]
 3: 0x1243917 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [/opt/containerbase/tools/node/22.22.3/bin/node]
 4: 0x1472825  [/opt/containerbase/tools/node/22.22.3/bin/node]
 5: 0x148c0b9 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/opt/containerbase/tools/node/22.22.3/bin/node]
 6: 0x14607b8 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/opt/containerbase/tools/node/22.22.3/bin/node]
 7: 0x14616e5 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/opt/containerbase/tools/node/22.22.3/bin/node]
 8: 0x1439a0e v8::internal::Factory::AllocateRaw(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/opt/containerbase/tools/node/22.22.3/bin/node]
 9: 0x1428844 v8::internal::FactoryBase<v8::internal::Factory>::AllocateRawWithImmortalMap(int, v8::internal::AllocationType, v8::internal::Tagged<v8::internal::Map>, v8::internal::AllocationAlignment) [/opt/containerbase/tools/node/22.22.3/bin/node]
10: 0x1429d0e v8::internal::FactoryBase<v8::internal::Factory>::NewRawOneByteString(int, v8::internal::AllocationType) [/opt/containerbase/tools/node/22.22.3/bin/node]
11: 0x159ee80 v8::internal::JsonParser<unsigned char>::MakeString(v8::internal::JsonString const&, v8::internal::Handle<v8::internal::String>) [/opt/containerbase/tools/node/22.22.3/bin/node]
12: 0x15a4f9e  [/opt/containerbase/tools/node/22.22.3/bin/node]
13: 0x15a750d v8::internal::JsonParser<unsigned char>::ParseJson(v8::internal::Handle<v8::internal::Object>) [/opt/containerbase/tools/node/22.22.3/bin/node]
14: 0x12c1519 v8::internal::Builtin_JsonParse(int, unsigned long*, v8::internal::Isolate*) [/opt/containerbase/tools/node/22.22.3/bin/node]
15: 0x1dfca36  [/opt/containerbase/tools/node/22.22.3/bin/node]
/usr/local/bin/node: line 18:  1593 Aborted                 (core dumped) /opt/containerbase/tools/node/22.22.3/bin/node "$@"

@tryghost-renovate tryghost-renovate Bot force-pushed the renovate/npm-form-data-2.5.4-vulnerability branch 4 times, most recently from 07aff8e to 3a96cc0 Compare June 16, 2026 03:35
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency form-data@<2.5.4 to v4 [SECURITY] Update dependency form-data@<2.5.4 to v4 [SECURITY] - autoclosed Jun 16, 2026
@tryghost-renovate tryghost-renovate Bot deleted the renovate/npm-form-data-2.5.4-vulnerability branch June 16, 2026 03:37
@tryghost-renovate tryghost-renovate Bot changed the title Update dependency form-data@<2.5.4 to v4 [SECURITY] - autoclosed Update dependency form-data@<2.5.4 to v4 [SECURITY] Jun 16, 2026
@tryghost-renovate tryghost-renovate Bot reopened this Jun 16, 2026
@tryghost-renovate tryghost-renovate Bot force-pushed the renovate/npm-form-data-2.5.4-vulnerability branch from f2bd720 to 3a96cc0 Compare June 16, 2026 06:18
@tryghost-renovate tryghost-renovate Bot force-pushed the renovate/npm-form-data-2.5.4-vulnerability branch 3 times, most recently from 3a96cc0 to cb8ed09 Compare June 16, 2026 06:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants