File upload is one of those features an assistant nails on the happy path and leaves dangerous everywhere else. It accepts the upload, writes it to disk, and returns success, which is all the feature seems to need. The safety of an upload, though, lives entirely in the checks around it, and those are exactly the parts that are not required to make it work. Four things get left out, and each one matters.
1. It trusts the file type
Generated upload code rarely checks what the file actually is, and when it does, it checks the extension or the content type the client sent, both of which the uploader controls. A file named image.png can hold a script. Validate the real type from the file's content, not from its name, and accept only the types you actually support.
Want to see exactly what Prbl flags? Watch it scan a demo app, no repo or account needed.
See a live scan →2. It stores uploads where the server will run them
The most serious outcome is an attacker uploading an executable file into a directory the web server serves, then requesting it to run code on your server. That depends on storing uploads inside the web root. Keep them outside it, or in object storage, and serve them back deliberately through your own handler, so a malicious file has nowhere to execute.
3. It keeps the attacker-controlled filename
Saving the file under the name the client provided invites two problems at once. The name can contain ../ sequences that escape your folder, which is path traversal, and it can collide with or overwrite an existing file. Generate a random name yourself and keep the original only as a display label if you need it.
4. It sets no size limit
With no cap on size, a single large upload, or many of them, can fill your disk or exhaust memory, which is a denial of service that costs the attacker almost nothing. Set a limit appropriate to what you accept and reject anything larger before you write it.
Putting it together
A safe upload validates the real content type, stores the file outside the web root under a random name, and enforces a size limit. None of these is complicated; they are just the steps that do not show up in a works-on-my-machine test. The full walkthrough, with code, is in the fix for an insecure file upload, and the pattern of the assistant shipping the happy path without the guards is the same one behind the insecure defaults it ships.
Frequently asked questions
What is the worst case with an insecure upload?
An attacker uploads an executable file, for example a server-side script, into a location the web server will run, then requests it and executes code on your server. That is the most severe outcome, and it usually depends on storing uploads inside the web root and trusting the file's extension. Even short of code execution, unchecked uploads enable overwriting other files, filling your disk, and serving malware from your domain.
Isn't checking the file extension enough to limit types?
No, because the extension is just part of the name the uploader chose, and it can be anything. A file named image.png can contain a script, and some setups will run it based on other signals. Validate the actual content, for example by checking the file's real type from its bytes, and do not rely on the extension or the client-supplied content type, both of which the attacker controls.
Why store uploads outside the web root?
So that even if a malicious file lands, the web server will not execute it as code, because it is not in a place the server serves and runs. Uploads kept outside the web root, or in object storage, are served back deliberately through your own handler rather than run directly. This single choice removes the upload-then-execute path that makes insecure uploads so dangerous.
Should I keep the original filename?
Better not to. The original name is attacker-controlled and invites both path traversal, where the name contains ../ to escape the folder, and collisions that overwrite other files. Generate a random name yourself, store the original only as a label in your database if you need to show it, and you sidestep both problems at once.
Check your upload handler
Uploads are easy to ship and easy to leave unguarded, and the missing checks do not show up until someone tests them on purpose. A scan reads the repo and flags an upload handler that skips validation, so you can add the checks before an attacker probes it. Run a free scan and see what your upload route accepts.