Join our Newsletter — 33% off our NHI Course
Home› Guides› File Upload Security Guide: Validation and Unrestricted Uploads
Guide Application Security

File Upload Security Guide: Validation and Unrestricted Uploads

← All guides
By Lalit Choda, NHI Mgmt Group Updated 18 October 2026 17 min read
On this page

Every file upload feature lets a stranger place bytes of their choosing on your infrastructure, and if those bytes are ever executed, rendered or parsed by something vulnerable, the upload becomes the way in. Avatars, CV portals, support attachments and CSV imports share the risk, and are often built as a storage problem rather than an input validation problem. This guide goes deeper than the overview in the Web Application Attacks Guide: it covers how unrestricted upload flaws arise, the order of validation checks, safe storage and serving, archives, malware scanning, content disarm and reconstruction, and web shell detection. It is for developers, application security engineers and release reviewers; attacks are described conceptually, with no payloads.

Key takeaways

  • Treat the upload as untrusted input end to end: the filename, declared type, bytes and anything extracted from them are all attacker-controlled.
  • Allowlist, then prove it: accept a few business-required extensions and confirm by parsing or re-encoding that the content really is that format; Content-Type headers and magic bytes are easy to fake.
  • Storage decides the blast radius: generated names, storage off the web root, no execute permission and no per-directory overrides turn a malicious upload into an inert blob.
  • Archives and rich documents need their own rules: zip slip, decompression bombs, macros and XML entities each need a specific control; most applications are safer refusing archives.
  • Assume one gets through: ATT&CK T1505.003 Web Shell detection centres on new files in web directories and web server processes spawning shells, both cheap to log.

How upload vulnerabilities arise

MITRE defines CWE-434, Unrestricted Upload of File with Dangerous Type, as a product that "allows the upload or transfer of dangerous file types that are automatically processed within its environment". The consequence it lists is code execution "if an uploaded file is interpreted and executed as code by the recipient". MITRE calls the common alternative name, unrestricted file upload, "insufficiently precise" because it could also mean missing size or count limits. In the OWASP Top 10:2025, CWE-434 is mapped to A06:2025 Insecure Design: most upload flaws are design decisions (where files land, who can fetch them, what parses them), not one missing check.

Term or weaknessWhat goes wrongPrimary control
Unrestricted or arbitrary file upload (CWE-434)Any type is accepted and ends up where it can be executed or renderedExtension allowlist, content verification, non-executable storage
Unauthenticated file uploadAnyone can write to the server; CWE cites CVE-2021-21972, an unauthenticated archive upload exploited in the wildAuthenticate every upload endpoint, including plugin installers
Incomplete identification of uploaded file variables (CWE-616)Legacy PHP code trusts global variables an attacker can overwrite via POST data or cookies, so it processes a file never uploaded, such as a system fileRead uploads only from $_FILES and verify them with is_uploaded_file() or move_uploaded_file()
Path traversal through the filename or archive entries (CWE-22)A supplied name resolves outside the upload directory and overwrites or creates files elsewhereGenerated names, canonicalise then check the base directory; CWE-22 sits in A01:2025 Broken Access Control

A malicious file upload need not be executable: an allowed type can still carry a parser exploit, a macro or a phishing lure. That is why the OWASP Web Security Testing Guide separates WSTG-BUSL-08 (unexpected file types) from WSTG-BUSL-09 (malicious files of allowed types).

What a malicious upload can do

RiskHow it works, conceptuallyControls that stop it
Web shell uploadA server-side script lands where the web server executes it and is requested by URL to run commands (ATT&CK T1505.003)Store outside the web root, no execute permission, generated names, extension allowlist, file integrity monitoring
Polyglot fileOne file is valid in two formats at once, such as a real image another parser reads as script or markup, so signature checks passRe-encode or transform content, serve with a fixed server-chosen type, never execute or render uploads inline on the main origin
Client-side active contentHTML, SVG or other script-capable files served from your domain run in other users' browsers, giving stored XSSSeparate download domain, Content-Disposition: attachment, X-Content-Type-Options: nosniff, refuse or sanitise SVG
Parser exploitationImage libraries, converters and XML parsers have their own flaws, including XXEPatched libraries, format restrictions, sandboxed processing, DTDs disabled
Resource exhaustionZip bombs, XML entity expansion and very large files exhaust disk, memory or CPUSize limits before and after decompression, entry and ratio limits, timeouts
Zip slipArchive entries carry relative or absolute paths so extraction writes outside the target folderValidate every entry's resolved path, or do not extract
Configuration overrideAn uploaded .htaccess or web.config changes how the server treats the directoryDisable per-directory overrides on upload paths (Apache AllowOverride None), block these names
Malware and phishing distributionYour trusted domain hosts malware or luresMalware scanning, quarantine before publication, abuse reporting

The validation pipeline, in order

File upload validation, and file type validation in particular, works when checks run in a fixed order, each narrowing what the next must handle; OWASP stresses that no single control is enough.

  1. Authenticate and authorise: identifiable users only, so quotas and audit work; protect browser forms against CSRF.
  2. Enforce size at the edge: request body limits at the reverse proxy and again in the application.
  3. Decode, then validate the name: the cheat sheet says extension checks must happen after the filename is decoded. Accept exactly one extension, compare case-insensitively (both CWE-434 mitigations) and reject names containing a colon, which blocks NTFS alternate data streams.
  4. File extension allowlist: list only the types the feature needs and pick the least risky: a CV portal might accept PDF and DOCX and nothing else. OWASP is blunt that "blocking specific extensions is a weak protection method on its own".
  5. MIME type validation: the client's Content-Type header "can be spoofed", so use it only as a quick consistency check against the allowlist, never as proof.
  6. Magic bytes: check the file signature matches the claimed type, but OWASP warns this "should not be used on its own, as bypassing it is pretty common and easy". Polyglots exploit exactly this.
  7. Parse or transform the content: open the file with a strict parser for the expected format, or rewrite it. For images, decode and re-encode to an allowed format and strip metadata; OWASP still cautions that "Rewriting does not guarantee that all malicious content is removed", so run the decoder sandboxed with resource limits.
  8. Scan and, where supported, disarm: pass the file to malware scanning and to content disarm and reconstruction for document formats, before anyone else can retrieve it.
  9. Store under a generated name in non-executable storage, with metadata (uploader, original name, verified type, size, hash, verdict) kept separately.
CheckWhat it provesWhat it does not prove
Extension allowlistThe name matches an approved typeThat the content is that type
Content-Type headerWhat the client claimsAnything the client did not want you to believe
Magic bytesThe first bytes resemble the formatThat the rest of the file is benign, or that no other parser reads it differently
Strict parse or re-encodeThe file is structurally valid in that formatThat the format's own features (macros, scripts) are safe
Malware scanNo known malicious pattern was foundAbsence of novel or targeted content

Why extension blocklist bypass keeps working: servers recognise more executable extensions than developers remember, different layers parse names differently (double extensions, case variations, trailing characters, truncating null bytes, alternate data streams), and a misconfigured server may execute an unexpected type. It is the most common file upload validation bypass; an allowlist plus generated names removes the class instead of chasing variants. MITRE records the pattern as CWE-184, Incomplete List of Disallowed Inputs, which can lead to CWE-434.

Filename sanitisation, storage and serving

Names and paths

  • Generate the stored name: OWASP calls a random UUID or GUID filename "essential". Keep the original name only as display metadata, encoded on output.
  • Filename sanitisation when names must be kept: enforce a maximum length, a safe character set (letters, digits, hyphens, spaces and periods), no leading period or hyphen, no consecutive periods and no path separators. NTFS 8.3 short names can alias existing files, another reason to generate names.
  • Map IDs to files: CWE calls this enforcement by conversion: clients request /files/8231, the server looks up the path, and user input never becomes part of it.
  • Canonicalise then check: where a path must be built, resolve it (for example with realpath()) and confirm it is still under the intended base directory.

Where files live

OWASP ranks storage options by security: a separate host or service first, outside the web root second, and inside the web root with write-only permissions only as a last resort. Private object storage without static website hosting is the usual modern form of the first. The NSA and ASD web shell guidance agrees: if the web server blocks access to the web-accessible directory, "Attackers are unable to upload a web shell". Give the application account write access only to the upload location and remove execute permission there. Files processed but never stored, such as an imported spreadsheet, need the same checks.

Serving uploads back

  • Serve from a separate cookieless domain so active content cannot act as your application.
  • Set the type yourself: send the verified Content-Type, add X-Content-Type-Options: nosniff so browsers do not guess, and use Content-Disposition: attachment for anything that does not need to display inline. See the Security Headers Guide.
  • Authorise downloads: check access on every request, prefer short-lived signed URLs to public buckets, and rate-limit downloads, since small requests can trigger large responses.

Archives, documents and other compound formats

  • Zip slip: CWE-22 lists CVE-2019-10743 and CVE-2020-4053 as "Zip Slip": entry names with traversal sequences make extraction write outside the target folder. Resolve each entry's destination and reject it unless it stays inside the extraction directory; reject absolute paths and links; extract into an empty, non-executable temporary directory.
  • Decompression bombs: limit uncompressed size, entry count, compression ratio and nesting depth, counting bytes as you stream rather than trusting header sizes (OWASP points to SEI CERT rule IDS04-J).
  • Prefer not to accept archives: OWASP does not recommend ZIP uploads because they can contain any file type; accept multiple files individually instead.
  • Office and PDF documents: macros, embedded JavaScript and attachments; convert or disarm. WSTG-BUSL-09 also lists CSV injection, where formulas in CSV files execute when opened in a spreadsheet.
  • XML-based formats and SVG: disable DTDs and external entities and cap entity expansion (which also stops XML bombs); SVG can carry script, so rasterise it on upload or refuse it.

Malware scanning and content disarm and reconstruction

Upload malware scanning and CDR solve different problems and are often used together.

ApproachStrengthLimitationBest for
Signature and heuristic anti-malware scanningCheap, fast, catches commodity malwareMisses novel and targeted files; OWASP notes cloud hash lookups raise data-leakage concernsEvery upload, as a baseline
Sandbox detonationObserves behaviour, catches some unknown malwareSlow, evasion-aware malware may sleepHigh-risk inbound documents, executables you must accept
Image re-encodingRemoves most appended or hidden contentDecoder bugs; not a guaranteeAvatars, photos, thumbnails
Content disarm and reconstructionRebuilds documents from known-good elements, dropping macros and active content regardless of whether they are known badMay break legitimate functionality; the engine parses hostile inputPDF and Office documents from the public

The NCSC's Safely Importing Data pattern explains why CDR works: complex formats are hard to verify, so transform them into a simple format, verify that strictly, then rebuild if needed. It warns that "Transformation should be a low side activity because it is inherently risky to parse and process untrusted content": run scanners and converters in an isolated, non-persistent worker with no production secrets. Use an asynchronous quarantine: uploads land in a private store, a worker scans and transforms them, and only clean output moves to where users can retrieve it. Test scanning with the EICAR test file, as WSTG-BUSL-09 recommends, never with live malware.

Designing the file upload endpoint

  • Chunked file upload: resumable protocols split a file across many requests. Limit chunk and total size per session, expire incomplete sessions, assemble in quarantine, and validate the assembled file, never individual chunks.
  • Direct-to-object-storage uploads: with a pre-signed URL or form policy the application never sees the bytes. Constrain the signed request (key prefix, content type, size range, short expiry) and validate from the storage event before release.
  • Quotas and rate limits: per-user and per-tenant limits stop storage abuse and make bulk probing noisy.
  • Where identity fits: the credentials that let the upload service, scanning worker and storage talk to each other are non-human identities. Scope the uploader role to write-only on the quarantine prefix and the publisher role to read quarantine and write clean storage. See the Service Account Security Guide.

Detecting web shells and upload abuse

ATT&CK v20 describes T1505.003 Web Shell as adversaries who "backdoor web servers with web shells to establish persistent access to systems". Its detection strategy, DET0394, focuses on behaviour: unexpected file creation in web directories followed by a web server process (such as w3wp.exe) launching a shell or script interpreter on Windows, and new .php or .sh files in /var/www/html followed by Apache or Nginx running utilities on Linux. Mitigations listed are M1042 Disable or Remove Feature or Program and M1018 User Account Management.

  • Process lineage: as the NSA and ASD guidance puts it, "it is uncommon for most benign web servers to launch the ipconfig utility". Alert on web server processes spawning cmd.exe, PowerShell or shells, using Sysmon Event ID 1 on Windows and auditd on Linux. See the Sysmon Guide.
  • File creation in web directories: Sysmon Event ID 11 (FileCreate) or file integrity monitoring on the web root and any directory the server executes.
  • Known-good comparison and traffic anomalies: diff deployed code against the release artefact (timestamps can be forged) and look for URIs requested only by one or two clients or unusual user agents.
  • Upload telemetry: log uploader, source address, names, verified type, size, hash and verdict, and alert on bursts of rejections from one account, a sign of filter probing.

Web shells also arrive without an upload form. In the ToolShell SharePoint exploitation, a deserialisation flaw gave code execution and a web shell written to disk read the ASP.NET machine keys; Microsoft's advice included hunting for the shell file and for w3wp.exe spawning PowerShell. The same detections catch both routes.

Implementation roadmap

  1. Inventory: every upload and import path, accepted types, where files land, whether that location is executable or public, and whether it needs authentication.
  2. Close the worst exposures first: remove execute permission and overrides from upload locations, require authentication everywhere, and move public uploads to a separate domain. These rarely break legitimate use.
  3. Run the pipeline in log-only mode for two to four weeks beside the existing handler, recording what it would reject, and review false rejections with product owners.
  4. Enforce one endpoint at a time behind a feature flag, so you can roll back instantly if legitimate files fail; keep rejected samples in quarantine.
  5. Add quarantine, scanning and CDR: start with the endpoints that accept documents from the public.
  6. Turn on detection: web server process and file creation alerts, upload telemetry into the SIEM.
  7. Keep testing: run WSTG-BUSL-08 and WSTG-BUSL-09 on each new upload feature, with zip bomb tests only under written approval because they can incur auto-scaling cost.

Decision guidance

  • Small organisations or a single application: private object storage, generated names, a short allowlist, image re-encoding and a managed malware scanning integration; refuse archives and SVG.
  • Large or regulated estates: build one shared upload service (quarantine, scanning, CDR, metadata, signed URLs) and make its use a release gate.
  • Choose CDR over scanning alone where documents from unknown parties are opened by staff; scanning alone can suffice where files are only stored and downloaded by their owner.
  • Do not rely on a web application firewall: the NSA and ASD guidance says such tools may block known malicious uploads but are "unlikely to detect web shell traffic". See the Web Application Firewall Guide.

Metrics that show the controls are working:

  • Share of inventoried upload endpoints using the standard pipeline, weighted by exposure.
  • Number of upload locations that are web-executable or served from the main application domain (target zero).
  • Share of uploads scanned before first retrieval, and median time in quarantine.
  • Rejected uploads by reason per endpoint, with spikes investigated.
  • Web server process lineage and web directory file creation alerts, and time to triage them.

Framework mapping

FrameworkReferenceRelevance
CWECWE-434, CWE-616, CWE-22, CWE-184Core upload, traversal and blocklist weaknesses
OWASP Top 10:2025A06:2025 Insecure Design (CWE-434); A01:2025 Broken Access Control (CWE-22)Design decisions; traversal
OWASP WSTGWSTG-BUSL-08, WSTG-BUSL-09Testing unexpected and malicious file uploads
MITRE ATT&CK v20T1505.003 Web Shell; M1042, M1018; DET0394What a successful upload leads to and how to detect it
NIST SP 800-53 Rev. 5SI-3 Malicious Code Protection, SI-10 Information Input Validation, SI-7 Software, Firmware, and Information Integrity, AC-6 Least PrivilegeScanning, validation, web content integrity, restricted rights
CIS Controls v8.1Control 16 Application Software Security; Control 10 Malware DefensesSecure development and testing; anti-malware on file stores
ISO/IEC 27001:2022 Annex AA.8.7 Protection against malware, A.8.26 Application security requirements, A.8.28 Secure codingMalware controls, upload requirements, implementation

Common failure patterns

  • Validating in the browser only: the check vanishes when someone sends the request directly; CWE-434 says to duplicate client checks on the server.
  • A growing extension blocklist: each penetration test adds an extension and the next finds another.
  • Uploads stored in the web root under the original name: the decision that turns an accepted script into a web shell; the NSA and ASD guidance notes internal applications such as content management systems are exposed too.
  • Trusting the image check: a polyglot or SVG passes the signature check, is served inline from the main domain and runs script in users' sessions.
  • Extracting archives in place without entry path or decompressed size checks, so one upload overwrites application files or fills the disk.
  • Scanners and converters with production access: the component that opens hostile files holds the application's credentials and network reach.

Practitioner checklist

  • Inventory every upload, import and installer path, and require authentication and authorisation on each.
  • Define a per-endpoint extension allowlist with the minimum business-required types.
  • Verify content by strict parsing or re-encoding; never rely on Content-Type or magic bytes alone.
  • Store under generated names in private, non-executable storage outside the web root, with per-directory overrides disabled.
  • Serve uploads from a separate cookieless domain with server-set Content-Type, nosniff and attachment disposition.
  • Refuse archives unless needed; otherwise validate every entry path and enforce decompressed size, entry count and ratio limits.
  • Quarantine, malware-scan and (for documents) disarm files before anyone else can retrieve them, in an isolated worker.
  • Apply the full pipeline to assembled chunked uploads and to direct-to-storage uploads.
  • Alert on web server processes spawning shells and on new files in web directories.
  • Test every new upload feature against WSTG-BUSL-08 and WSTG-BUSL-09 before release.

Standards and references

Related NHI Mgmt Group resources: Web Application Attacks Guide · Secure Coding Guide · OWASP Top 10 Guide · Malware Guide · Persistence Techniques Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 18 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org