Cross-Site Scripting (XSS) via File Upload

What Is the Vulnerability?

Cross-Site Scripting (XSS) via file upload occurs when a web application allows users to upload files and then serves those files back to users without validating or sanitizing their content or file type. If the uploaded file contains embedded JavaScript or executable code, and is later rendered in the browser, the attacker’s script can execute in the context of the user’s session.

Common variants:

1. Stored XSS via Uploaded HTML File

If a user can upload .html, .svg, or .xml files and the server allows them to be accessed as-is, the attacker can inject JavaScript.
stored_xss_via_upload

If the app stores and serves this file directly (e.g., via https://example.com/uploads/malicious.html), anyone visiting that link will execute the script.

2. XSS via Image Metadata

Some attackers embed scripts into image file metadata (e.g., in SVG, PDF, or even malformed JPEGs), which are rendered by vulnerable image viewers or document readers in the browser.

Even if the file content is safe, malicious scripts can be injected through:

  • File names (<script>alert(1)</script>.jpg)
  • Form fields associated with file uploads (e.g., description, title)

If these values are later rendered in HTML without proper escaping, they can also trigger XSS.

Cross-Site Scripting via File Upload - image

What’s the Impact?

1. Account Hijacking :

Session cookies or tokens can be stolen via malicious scripts.


2. Defacement or Fake Content

Malicious scripts can rewrite DOM content, impersonate UI elements, or trick users.


3. Sensitive Data Theft

XSS scripts can keylog input fields or exfiltrate CSRF tokens and personal data.

Solution to Fix the Vulnerability

To prevent XSS via file upload, secure both the upload process and how files are stored/served.

  1. Block Dangerous File Types

    Reject any file extensions or MIME types that browsers render as code:
    • .html, .htm, .svg, .xml, .js, .php, .jsp, .aspx
    • Allow only safe types like .jpg, .png, .gif, .pdf (if needed)
    Validate both file extension and MIME type using libraries like:
    • python-magic (Python)
    • file-type (Node.js)

  2. Use Content-Disposition to Force Download

    Prevent browsers from rendering files by setting headers.
    use_content_disposition_to_force
    This forces the browser to download the file instead of rendering it in-page.

  3. Strip or Sanitize Metadata

    Use image processing tools (like ExifTool or ImageMagick) to remove or sanitize metadata that might contain scripts.

  4. Escape All Dynamic Content in HTML

    Whether displaying filenames, captions, or custom fields — escape them properly using:
    • htmlspecialchars() in PHP
    • {{ value | escape }} in Jinja2 (Python Flask)
    • res.text(value) in Express (Node.js with templating)

XSS via file upload is particularly dangerous because it looks like a harmless image or document, but silently compromises user sessions. Sanitize everything, validate every file, and serve user content in a sandbox.