File Upload Security Policy Builder

Turn upload requirements into a concrete policy - allowed types, size caps, storage, renaming, Content-Disposition, authorisation - with framework snippets that verify on the server.

Runs locally

Everything happens in your browser. What you paste or drop here is never uploaded, logged or stored.

Use the tool

Comma separated. An allow-list, never a block-list.

Every control that matters runs on the server

This is the principle the generated code is built around, and it is worth stating before anything else: client-side validation is a convenience for the person uploading and is not a security control. An attacker posts to your endpoint directly and never runs your JavaScript. The accept attribute on a file input, a size check in the browser, a MIME filter in your upload widget - none of it is ever reached.

So this tool generates server-side code, and the policy document it produces says so on the last line.

Validate the bytes, not the name

The extension is chosen by whoever named the file. The Content-Type is sent by the client. Both are hints; neither is evidence. The generated code uses the extension only to decide which signature to expect, and then checks the actual bytes against it.

Check an individual file against its claims with MIME Type and Magic Byte Checker.

Re-encoding beats validating

A signature check confirms a file starts like an image. It says nothing about the rest of it. A valid JPEG can carry a PHP payload in a comment segment, hostile EXIF, or be a polyglot that is simultaneously a valid archive.

Re-encoding solves the whole class at once. Decode the image, re-encode it, store only the output, and discard what you were given. Anything that was not image data does not survive - and you strip GPS coordinates from photos as a side effect, which is a privacy improvement you get for nothing.

Generate the stored filename yourself

A client-supplied filename can contain path traversal, a null byte, a reserved Windows device name (CON, NUL, LPT1), or simply the name of a file you already have - which overwrites it. Sanitising filenames correctly across platforms is genuinely hard and has been got wrong repeatedly by people who knew what they were doing.

Do not sanitise. Generate a UUID, store under that, and keep the original name as metadata that never becomes part of a path. The generated code also resolves the final path and confirms it is still inside the upload directory, which catches traversal even if the name check is ever loosened.

Serve user content from a separate origin

This is the control that saves you when the others fail. Anything served from your origin runs with your origin's privileges - an uploaded HTML or SVG file becomes stored XSS with access to your session cookies.

Every large site that hosts user content does this: a separate hostname, deliberately outside the domain that holds the session. GitHub, Google and Discord all do it. Combined with Content-Disposition: attachment and X-Content-Type-Options: nosniff, it means a hostile upload cannot reach anything even if it gets past validation entirely.

Scanning must fail closed

If you scan uploads, a file that cannot be scanned must be quarantined, not released. Failing open when the scanner is unavailable removes the control precisely when something is wrong - and scanner outages are exactly when a determined attacker would prefer to upload.

ZIP-based formats need their own limits

If you accept DOCX, XLSX or plain archives, bound the entry count, the total uncompressed size and the compression ratio before extracting anything. A zip bomb is a few kilobytes that expands to gigabytes, and the default behaviour of most extraction libraries is to try.

Everything on this page is generated in your browser. Nothing is transmitted.

Frequently asked questions

Is client-side validation worth doing at all?

As user experience, yes - telling someone immediately that their file is too large is kinder than a failed upload. As security, no. It is not reached by anyone who does not want it to be.

Should I block dangerous extensions instead of allow-listing safe ones?

No. Block-lists are always incomplete - there is always another extension, another casing, another double extension, another platform-specific alias. Allow-list what you need and reject everything else.

Is re-encoding really necessary if I check the signature?

A signature check reads the first few bytes. Re-encoding validates the entire file by the only test that counts - whether a decoder can actually read it - and discards everything that was not image data. It is the stronger control by some distance.

Why a separate origin rather than just Content-Disposition?

Because Content-Disposition is one header on one code path, and same-origin means a mistake anywhere becomes stored XSS with access to your session. A separate origin makes the failure mode contained rather than catastrophic.

Does this tool see my configuration?

No. The policy and code are assembled in your browser from the options you select. Nothing is transmitted.

References

What this tool can and cannot tell you. It reports what is present in the input you provide. It cannot see anything you did not give it, and a clean result means nothing was found in that input - not that the wider system is secure.

Security guidance here follows current published sources - OWASP, MDN, the relevant RFCs, NIST, CISA, FIRST and MITRE - which are linked beside the specific claims they support.

Rate this tool

Was this tool useful? Your feedback helps us improve it.

No ratings yet — be the first to rate this tool.
Your rating (required)
0 / 2000

Please do not include passwords, payment details or other sensitive information.

Your feedback is sent privately to the A2Z.Tools team and will not be posted publicly.