← All fixes

Fix it

Insecure file upload, how to fix it

High severityCWE-434 (Unrestricted Upload of File with Dangerous Type)
We scanned nearly 2,000 AI-built apps and 1 in 8 shipped a high-severity flaw. Is this one in yours?Scan free →

An upload handler that trusts the file's name and type, and stores it where the server can execute or serve it, is a common path to remote code execution or stored cross-site scripting. Validate the type against an allowlist, give the file a new random name, and store it somewhere it will never be executed.

Why it's a problem

If an attacker can upload a script and then request it, the server may execute it, which is full compromise. Even without execution, an uploaded HTML or SVG file served from your domain can carry cross-site scripting. Trusting the original filename also invites path traversal, writing the file outside the intended folder.

The pattern

// trusts the uploaded name and type
const dest = path.join("public/uploads", file.originalname);
fs.writeFileSync(dest, file.buffer);

The fix

// allowlist type, random name, non-served storage
const allowed = { "image/png": ".png", "image/jpeg": ".jpg" };
const ext = allowed[file.mimetype];
if (!ext) return res.sendStatus(400);
const name = crypto.randomUUID() + ext;
fs.writeFileSync(path.join("/var/uploads", name), file.buffer);

Why AI tools write this

Saving the upload under its original name into a public folder is the most direct way to make an upload feature work and be visible, so it is the natural completion. It works fine for ordinary images in testing, and the danger only appears with a malicious file.

The quick fix

  • Validate the content type against an allowlist; do not trust the file extension alone.
  • Give each upload a new random filename, never the user-supplied one.
  • Store uploads outside the web root so they cannot be executed or directly served.

Common questions

Why do I need to check MIME type if I am already checking the file extension?

A user can rename a .php or .js file to .jpg. Verify the actual content type by reading the file's magic bytes, not just the extension or the Content-Type the client sent.

Is storing uploads in an S3 bucket automatically safe?

Safer than storing in the web root, but only if the bucket is not publicly readable and content is not served with executable MIME types. Confirm the bucket policy does not allow anonymous reads.

How do I generate a safe random filename for uploads?

Use crypto.randomUUID() or crypto.randomBytes(16).toString('hex') appended with the validated extension. Never reuse or trust the user-supplied filename.

Want to know if this pattern is already in something you shipped? Scan your live app or a public repo free, no account needed.

Scan my app →

Related: related: path traversal

Catch this automatically: scan your GitHub repo · website vulnerability scanner · review every pull request · SAST for AI code · OWASP Top 10 for AI code

Insecure File Upload, Why It's Dangerous and How to Fix It | Prbl