Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter III - Web / 04. File Uploads

File Uploads

File Upload vulnerabilities happen when the application accepts attacker-controlled files without controlling what they are, where they are stored, how they are named, or how they are served.

The primitive is untrusted file handling. The uploaded file is attacker-controlled input, but it often crosses into storage, parsing, preview, download, antivirus, image processing, archive extraction, or public serving.

Common upload risks include:

  • Dangerous file types
  • Active browser content
  • Server-executed extensions
  • Client-controlled filenames
  • Path traversal through filenames
  • MIME type spoofing
  • Extension blacklist bypasses
  • Image or document parser bugs
  • Archive extraction attacks
  • Stored XSS through uploaded HTML, SVG, or PDF content
  • Public access to private uploads

Common upload surfaces include:

  • Profile pictures
  • Attachments
  • Support tickets
  • Import features
  • Avatar uploaders
  • Document portals
  • Report builders
  • Markdown image uploads
  • Admin import/export tools
  • Image resizing or thumbnail generation

When enumerating file upload issues, identify:

  • Which extensions are accepted
  • Which content types are accepted
  • Whether the server trusts the client-provided MIME type
  • Whether the filename is preserved
  • Whether the stored filename is predictable
  • Whether files are served from the same origin as the application
  • Whether uploaded files are rendered inline or downloaded
  • Whether uploaded files are processed by server-side tools
  • Whether the file is public, private, or owner-scoped
  • Whether the application checks magic bytes or only extensions

Types

Unrestricted upload means the application accepts dangerous file types.

upload proof.html
open proof.html from the application origin

Weak extension filtering means the application blocks a few known extensions but misses other dangerous formats.

block .php
allow .html
allow .svg

MIME trust means the application believes the Content-Type header supplied by the client.

Content-Type: image/svg+xml

Unsafe serving means the application stores a file safely enough, then serves it in a dangerous way.

inline active content
same-origin upload domain
missing X-Content-Type-Options: nosniff

Unsafe processing means the uploaded file is handed to a parser, converter, archive extractor, or image tool that has its own attack surface.


Enumeration

Start with harmless files:

proof.txt
proof.png
proof.html
proof.svg

Test extension handling:

proof.html
proof.svg
proof.php.txt
proof.txt.html
PROOF.HTML

Test MIME handling:

text/html
image/svg+xml
image/png
application/octet-stream

Compare:

  • Upload response
  • Stored filename
  • Stored path
  • Public URL
  • Response Content-Type
  • Whether the file renders inline
  • Whether browser script executes
  • Whether another user can access the file

Interesting findings include:

  • HTML uploads executing JavaScript
  • SVG uploads executing JavaScript
  • The original filename being reused
  • Extension checks that only block a few known values
  • The server trusting client-supplied Content-Type
  • Files served from the main application origin
  • Private files accessible without owner checks
  • Uploaded files processed by converters or thumbnailers

Exploit

  1. Upload a normal file.
proof.txt
  1. Confirm where it is stored and how it is served.
/file-uploads/files/basic/proof.txt
  1. Upload harmless active browser content.
<!doctype html>
<script>
document.body.innerText = document.domain;
</script>
  1. Open the uploaded file from the application origin.
/file-uploads/files/basic/proof.html
  1. If JavaScript runs, the upload feature allows stored active content in the application's origin.

  2. Test weak filters with alternate extensions or content types.

proof.html
proof.svg
  1. Stop once impact is proven.

In this Flask lab, the impact is active browser content from the trusted origin. On a stack that executes uploaded server-side extensions, impact can be much higher.


Remediation

Patch file upload issues by controlling the full upload lifecycle:

  • Allow only required file types.
  • Validate file content with magic bytes, not only extensions.
  • Generate server-side filenames.
  • Store uploads outside executable web roots.
  • Serve untrusted uploads from a separate origin when possible.
  • Force download for files that do not need inline rendering.
  • Block active formats such as HTML and SVG unless they are explicitly required and safely isolated.
  • Set X-Content-Type-Options: nosniff.
  • Enforce size limits.
  • Re-encode images instead of trusting uploaded image bytes.
  • Apply authorization checks to upload read, update, delete, and download routes.
  • Log rejected uploads and suspicious file types.

Safe upload handling is not one check. It is a chain of controls.