Safeguard
Open Source

form-data npm Package: Usage, Health, and Security Review

The form-data npm package builds multipart request bodies for half the Node.js ecosystem — and its 2025 predictable-boundary CVE showed how a one-line randomness choice becomes an injection primitive.

Aisha Rahman
Security Analyst
6 min read

The form-data npm package is the standard library for building multipart/form-data request bodies in Node.js, and in July 2025 it picked up CVE-2025-7783 — a predictable-boundary flaw that turned a humble randomness shortcut into an HTTP injection primitive. Because form-data sits under axios, superagent, and countless SDKs, the advisory landed in nearly every Node.js dependency tree at once. This review covers what the package does, how the vulnerability works, which versions are safe, and what the incident says about auditing foundational utilities.

What form-data does

HTTP file uploads and mixed text-plus-binary submissions use the multipart/form-data encoding: the body is a sequence of parts separated by a boundary string declared in the Content-Type header. The npm form data package (form-data on the registry) constructs those bodies as streams, mirroring the browser's FormData API for server-side code:

const FormData = require("form-data");
const fs = require("fs");

const form = new FormData();
form.append("report", fs.createReadStream("./q3.pdf"));
form.append("notes", userSuppliedText);

form.submit("https://api.example.com/upload");

On the wire, that becomes:

Content-Type: multipart/form-data; boundary=--------------------------834027168742

with each field wrapped between occurrences of the boundary. You rarely install form-data deliberately; it arrives transitively — most famously as a dependency of axios and of the (deprecated but immortal) request package — which is why its weekly downloads sit in the tens of millions and why any advisory against it has ecosystem-wide reach.

CVE-2025-7783: when the boundary is guessable

The boundary string has a quiet security job: the receiving parser splits the body wherever the boundary appears, so a sender must pick a boundary the field contents cannot collide with, and — crucially — one an attacker cannot predict. Vulnerable form-data versions generated it with Math.random().

Math.random() is not cryptographically secure. Its underlying generator (xorshift128+ in V8) can have its internal state recovered from a handful of observed outputs, after which every future output is predictable. The attack chain the advisory (GHSA-fjxv-7rqg-78g4) describes requires two conditions:

  1. The attacker can observe other Math.random() values from the same process — for example, an API that exposes random-looking IDs, tokens, or cache-busters generated from the same PRNG.
  2. The attacker controls one field's value in a multipart request the server sends via form-data.

With the PRNG state recovered, the attacker predicts the boundary the server will use for its next outbound multipart request, then embeds that exact boundary string inside their controlled field. The receiving parser sees the injected boundary as a real part separator, and the attacker's field now contains complete forged parts: extra form fields (role=admin), a smuggled file part, or overrides of fields the server set after the attacker's. It is HTTP parameter pollution inside the multipart body — request splitting's quieter cousin — and depending on what the upstream service does with the forged fields, the impact ranges from validation bypass to privilege escalation.

The fix is exactly what you would expect: patched releases replace Math.random() with cryptographically secure random generation for the boundary.

Affected and fixed versions

Straight from the advisory:

LineVulnerableFixed
2.xbelow 2.5.42.5.4
3.x3.0.0 – 3.0.33.0.4
4.x4.0.0 – 4.0.34.0.4

The multi-line backport matters: enormous amounts of legacy code pin form-data 2.x via the deprecated request package, and those trees got a patch without needing a major migration. Check what you actually resolve:

npm ls form-data

Expect multiple instances at different versions in a mature repo — each one needs to clear the bar independently. This is bread-and-butter work for SCA scanning: the advisory's real-world remediation was mostly "regenerate the lockfile and let axios's patched range flow through," but only a resolved-version scan tells you when a stubborn transitive pin keeps a vulnerable copy alive. Safeguard, like other SCA tools, will also show which direct dependency owns each vulnerable path so you upgrade the right thing.

Package health beyond the CVE

form-data scores as a healthy foundational package: maintained under a community org with multiple contributors, conservative release cadence, minimal dependency footprint (asynckit, combined-stream, mime-types), and prompt coordinated handling of the 2025 advisory with backports across three major lines — the response you want from infrastructure code. Its API has been stable for a decade, which cuts both ways: little churn risk, but also long-lived copies of old versions fossilized in legacy lockfiles.

One forward-looking note: as with node-fetch, the platform has been absorbing this territory. Node.js ships a native, spec-compliant FormData (usable with native fetch) in all currently supported versions, and new code that just needs to POST a file can often use it with zero dependencies. Existing integrations built on axios or older HTTP stacks will keep form-data in the tree for years, which is fine — patched, it is a solid dependency.

Lessons for reviewing utility packages

Three takeaways generalize well beyond this package.

Randomness is a security surface even in "non-security" code. Nobody files a threat model for a boundary string. The rule that catches this class in review: any value that must be unpredictable to someone — boundaries, IDs sent to third parties, filenames in shared storage — gets crypto.randomBytes/crypto.randomUUID, not Math.random(). The cost difference is nil; defaulting to the CSPRNG everywhere is cheaper than litigating which values are attacker-relevant.

Exploitability conditions are context, not comfort. CVE-2025-7783 needs an observable PRNG output and a controllable field. Plenty of services meet both without realizing it. Version-range matching tells you exposure; only knowing your data flows tells you risk — a good argument for pairing SCA findings with reachability analysis rather than bulk-dismissing "unlikely" advisories.

Foundational packages deserve upgrade drills. When a base-layer package advisories, the work is lockfile surgery across every service at once. Teams that had rehearsed bulk dependency updates cleared this one in an afternoon; teams that hadn't discovered ancient pins the hard way. If that second description stings, the dependency-management modules in Safeguard Academy are a decent place to start building the muscle.

FAQ

What is CVE-2025-7783 in the form-data npm package?

It is a predictable-randomness flaw: vulnerable versions generated multipart boundaries with Math.random(). An attacker who could recover the PRNG state from other observed outputs and control one form field could inject the predicted boundary, forging additional multipart parts and polluting fields in server-sent requests.

Which form-data versions are safe?

2.5.4 or later on the 2.x line, 3.0.4 or later on 3.x, and 4.0.4 or later on 4.x. Run npm ls form-data and verify every resolved instance — most projects pull it transitively through axios, request, or SDKs.

Do I still need form-data in new Node.js code?

Often not. Current Node.js versions include a native FormData that works with built-in fetch for straightforward multipart uploads. form-data remains the right tool inside axios-based stacks and older HTTP clients that expect its stream-based API.

Why is Math.random() a problem for boundaries?

Because V8's Math.random() state can be reconstructed from a few observed outputs, making all future values predictable. A predicted boundary lets an attacker place a real part separator inside a field they control, which the receiving parser then honors as forged form parts.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.