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 locallyEverything happens in your browser. What you paste or drop here is never uploaded, logged or stored.
Use the tool
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
Related tools
Other Tools
Popular tools from across A2Z
Rate this tool
Was this tool useful? Your feedback helps us improve it.