Formidable is a widely used Node.js npm package for parsing form data, especially multipart file uploads, and its security history centers on filename handling rather than a flaw in the parser itself. If you handle uploads in an Express or plain Node service, there is a good chance formidable is somewhere in your tree. This review covers the vulnerabilities that have been assigned against it, the important nuance behind why they were disputed, and the configuration that keeps uploads safe.
What formidable does
Formidable parses incoming multipart/form-data requests — the format browsers use to submit file uploads — and writes the uploaded files to disk (or streams them) while exposing the fields to your handler. A minimal use looks like this:
import formidable from "formidable";
const form = formidable({ uploadDir: "/var/app/uploads", keepExtensions: true });
const [fields, files] = await form.parse(req);
The library is mature and popular, which is exactly why its security posture is worth understanding rather than assuming.
The CVE history, told accurately
Two CVE IDs have been assigned against formidable, and both are really about filenames, not memory corruption or code execution in the parser.
CVE-2022-29622 was filed as an arbitrary file upload vulnerability in formidable, carrying a high CVSS score, on the claim that a crafted filename could lead to arbitrary code execution. According to the Snyk advisory, the issue was addressed in version 3.2.4. What makes this one important to understand is that it was disputed. The maintainers and other parties argued that uploading arbitrary files is a legitimate, intended use of an upload parser, that all versions expose configuration options controlling how files are named and stored, and that exploitation required additional vulnerable code outside formidable. The consensus that emerged was that sanitizing filenames is the application's responsibility, not something the parser should silently impose. Treat CVE-2022-29622 as a prompt to review your own filename handling, not as proof the library is broken.
CVE-2025-46653 was later assigned for a filename-prediction weakness. The advisory describes versions in the 2.1.0 through 3.x range before 3.5.3 as affected, with the fix landing in 3.5.3. The concern here is predictability of generated filenames rather than direct code execution.
The practical guidance: run a recent version — at least 3.5.3 — and, regardless of version, control filename handling yourself.
The real risk is how you handle filenames
The dispute over CVE-2022-29622 points at the actual lesson. An upload parser writes whatever bytes arrive; the danger is what your code does with the client-supplied filename afterward. Two failure modes recur.
First, path traversal. If you take the original filename from the upload and join it to a directory without sanitizing, a filename like ../../etc/something can escape your intended directory. Never trust the client filename as a path component:
import path from "node:path";
import crypto from "node:crypto";
// do NOT use file.originalFilename directly as the stored name
const safeName = crypto.randomUUID() + path.extname(file.originalFilename ?? "");
Generating your own random storage name and only borrowing a sanitized extension removes both traversal and filename-prediction concerns in one move.
Second, unrestricted upload of dangerous content. Enforce a size limit and validate the content type — and validate it by sniffing the actual bytes, not by trusting the client-declared MIME type, which is trivially forged. Formidable exposes options for this:
const form = formidable({
uploadDir: "/var/app/uploads",
maxFileSize: 5 * 1024 * 1024, // 5 MB cap
keepExtensions: false, // you control the name
});
Store uploads outside the web root so an uploaded file can never be requested and executed as a script, and serve them back through a controlled handler rather than directly.
Keeping the dependency current
Because npm formidable is usually a transitive dependency of some upload middleware, teams often do not realize which version they are running. Check it:
npm ls formidable
If that shows an old 2.x or an early 3.x, upgrade. When formidable comes in transitively through another package, you may need to update the parent or add a resolution/override to force a patched version. This is exactly the kind of buried, version-specific exposure an SCA tool such as Safeguard surfaces automatically — it flags the vulnerable formidable deep in your tree even when it never appears in your package.json. The SCA product page explains the transitive-detection mechanics.
FAQ
Is the formidable npm package safe to use?
Yes, when kept current and configured correctly. Run version 3.5.3 or later, generate your own storage filenames instead of trusting the client-supplied name, enforce a size limit, validate content by sniffing bytes, and store uploads outside the web root. The parser itself is mature; most real risk comes from how the surrounding code handles filenames.
What was CVE-2022-29622 in formidable?
It was reported as an arbitrary file upload vulnerability tied to crafted filenames, fixed in version 3.2.4. It was notably disputed: uploading arbitrary files is intended behavior for an upload parser, all versions expose filename-handling options, and exploitation required additional vulnerable code. The takeaway is to sanitize filenames in your own application.
How do I check which version of formidable I have?
Run npm ls formidable from your project root. It prints the installed version and shows whether it is a direct or transitive dependency. If it arrives through another package, update the parent or add an override to pull in a patched version.
How do I prevent path traversal from uploaded filenames?
Never use the client-supplied filename as a path component. Generate a random storage name (for example with crypto.randomUUID()) and, if you need an extension, take only a sanitized extension via path.extname. Store files outside the web root and serve them through a controlled handler.