Log each upload as a short chain of events: attempt, validation result, malware scan result, and stored object ID, each tied to the user and request. Record the original filename as untrusted text and a random storage name. Do not log file contents. Alert on repeated validation failures and scan detections.
Why uploads are worth their own events
File upload is one of the few features where an anonymous or low privilege user hands your server arbitrary bytes. When something goes wrong, you want to know who sent what, what the checks said, and where the file went.
The OWASP Logging Cheat Sheet names file uploads among higher risk functionality, next to data import and export and deserialization failures. Its Logging Vocabulary gives example event names for uploads, including upload_complete, upload_stored, upload_validation and upload_delete.
An event chain
| Stage | Event | Useful fields |
|---|---|---|
| Received | upload_complete | User ID, declared type, size, original filename (untrusted) |
| Checked | upload_validation | Check name, pass or fail, detected type |
| Scanned | upload_validation with scan result | Scanner name, result such as clean or detected |
| Stored | upload_stored | Storage ID, location class, hash |
| Removed | upload_delete | Actor, storage ID, reason |
| Accessed | file_download | User, storage ID, result |
The vocabulary notes that fields after the event name are optional and should be weighed against privacy duties.
Store a hash of the content in the log, not the content. It lets you find the same file again, for example if a scanner later flags it.
Storage choices that help your logs
The OWASP File Upload Cheat Sheet recommends generating a random name, such as a UUID, and calls that essential. If you must keep user supplied names, limit length and characters and avoid leading periods or hyphens. For location, it ranks a different host first and a place outside the webroot second, and says to disable per directory configuration overrides in upload directories. It also recommends scanning with antivirus or a sandbox where available.
Random storage names mean your log can safely refer to the storage ID. The original name, which an attacker controls, belongs in a field marked untrusted and escaped for log injection. See log injection and forged entries.
Alert rules
- Many validation failures from one user in a short time.
- Any scanner detection, with the user and hash.
- A declared type that does not match the detected type, repeated.
- A user uploading unusually many or unusually large files.
- A download of a flagged file after it was marked bad.
Steps to add it
- Wrap the upload handler so every path, success or failure, ends in an event.
- Make the validation step emit the name of the check that failed.
- Emit the storage ID only after the file is safely stored.
- Test with a harmless test file and a file with a mismatched extension.
- Review retention: upload logs may include personal filenames.
Quick check
Should I log the uploaded filename?
Yes, as untrusted text, escaped, and kept separate from the storage name. Filenames can carry personal data, so apply your retention rules.
Do I need to scan every file?
OWASP recommends scanning with an antivirus or sandbox if available. Log the scan outcome either way.
Safeguard's SBOM and dependency scanning covers the file handling libraries you depend on. Try a free scan at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.