Vulnerability library  /  File upload

File upload flaws

File upload

File upload flaws let users store files with unsafe content, names, locations, or permissions. Consequences range from stored script execution and malware distribution to server-side code execution.

Also known as
Unrestricted file upload · Unsafe file upload · Malicious file upload
Typical severity · Medium to Critical
Last updated
On this page: What it is
  1. 1 · What it is
  2. 2 · Why it matters
  3. 3 · Examples
  4. 4 · How to fix it
  5. 5 · How to test for it
  6. References
  7. Related

What it is#

Uploading a file crosses several trust boundaries at once: filename, declared content type, actual bytes, metadata, size, storage location, and later processing. A flaw in any of them can make the feature unsafe.

Checking only the filename extension or browser-provided MIME type is not sufficient. Files can contain active content, multiple valid formats, decompression bombs, traversal names, parser exploits, or content that becomes dangerous only when served from the application's origin.

Risk also depends on what happens next. Image resizing, document conversion, archive extraction, antivirus scanning, thumbnail generation, and indexing all expose additional parsers.

Why it matters#

  • Execute server-side code when an uploaded file is stored in an executable web directory.
  • Run script in another user's browser when HTML, SVG, or active documents are served inline.
  • Distribute malware from a trusted domain.
  • Overwrite files through traversal, collisions, or unsafe archive extraction.
  • Exhaust disk, memory, or CPU with large files, archives, or parser-heavy content.
  • Exploit vulnerable media, image, document, or archive-processing libraries.
  • Expose private files through predictable names or missing download authorization.
Typical severity

Medium when the effect is limited to storage abuse or controlled content. High to critical when uploads enable stored script execution, server-side code execution, cross-tenant access, or compromise of a privileged processing worker. Actual severity depends on context: who is affected, what data or actions are reachable, and existing controls.

Examples#

✕ Vulnerablephp
<?php
// Vulnerable: trusts the original name and stores it beneath the web root.
$destination = __DIR__ . '/public/uploads/' . $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], $destination);
echo '/uploads/' . $_FILES['file']['name'];
✓ Fixedphp
<?php
// Fixed: validate actual type, generate the name, and store outside the web root.
$allowed = [
    'image/jpeg' => 'jpg',
    'image/png'  => 'png',
];

if ($_FILES['file']['size'] > 5 * 1024 * 1024) {
    http_response_code(413);
    exit;
}

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);
if (!isset($allowed[$mime])) {
    http_response_code(415);
    exit;
}

$storageName = bin2hex(random_bytes(24)) . '.' . $allowed[$mime];
$destination = '/srv/app-uploads/' . $storageName;
if (!move_uploaded_file($_FILES['file']['tmp_name'], $destination)) {
    http_response_code(500);
}

The download handler should look up the generated storage key after authorization and return a safe Content-Type and Content-Disposition.

How to fix it#

1. Allowlist necessary formats. Define accepted extensions, actual media types, maximum size, dimensions, and document characteristics for each upload purpose.

2. Validate bytes, not client claims. Inspect file signatures and parse with a maintained library. MIME sniffing alone cannot prove a complex file is safe.

3. Generate storage names. Never use the original filename as a path. Store the display name as encoded metadata with length and character limits.

4. Store outside executable and public directories. Serve downloads through an authorized handler or a separate object-storage origin configured not to execute or interpret content.

5. Serve risky content as an attachment. Set a controlled Content-Type, Content-Disposition: attachment, and X-Content-Type-Options: nosniff. Use a separate untrusted-content domain when users must view active formats.

6. Isolate processing. Scan and convert files in a low-privilege worker with no customer credentials, restricted network access, read-only tooling, timeouts, and resource quotas.

7. Re-encode when possible. Decode and regenerate images or documents into a known-safe subset rather than preserving arbitrary embedded content and metadata.

8. Quarantine before release. Keep uploads unavailable until required scanning and validation completes. Record scanner version and result.

9. Protect every file operation. Enforce ownership on upload, status, preview, and download routes. Set tenant quotas, retention, and deletion controls.

How to test for it#

  • Upload benign files with incorrect extensions and MIME types and confirm validation uses actual content.
  • Test double extensions, uppercase variants, trailing dots, long names, Unicode names, and traversal-like names without uploading executable code.
  • Upload harmless HTML and SVG fixtures and confirm they are rejected or served from an isolated origin as attachments.
  • Exercise maximum size, image dimensions, archive expansion, file count, and processing-time limits using approved test fixtures.
  • Verify files are stored outside the web root under generated names and cannot be fetched without authorization.
  • Test two users and two tenants to confirm upload status, preview, and download controls remain isolated.
  • Confirm processing failures leave the file quarantined and that temporary files are removed.
  • Review object-storage permissions, CDN content-type behavior, and web-server execution settings in the deployed environment.

References#

Permalinklibrary.infinity8labs.com/file-upload-flaws/JSON
Found this in Breachvane? Your finding links here for background. Evidence, affected assets and retest status are in your Breachvane ↗ (opens in a new tab) workspace. Need help fixing it? Talk to us.