RedTeam Nexus Labs
Module 11 · Lesson 03 // File Upload

storage

File Upload · CTF

Freereading · 10 min
On this page
LESSON

Overview

Validating and handling a file is only half the job. Where you store an uploaded file and how you serve it back determine whether an accepted file can still cause harm. This lesson covers safe storage: keeping uploaded files outside the webroot, serving them so they are never executed or interpreted as active content, and isolating them from the rest of the application. As always, these ideas are practiced in authorized, isolated environments so you can build storage that fails safe.

Learning objectives

  • Explain why the storage location controls a file's blast radius.
  • Describe storing uploads outside the webroot and serving them safely.
  • Apply isolation and least-privilege to uploaded content.

Core concept

The danger of a malicious upload is realized at the moment the file is interpreted or executed. A server-side script sitting harmlessly in a database or an object store does nothing; the same script placed inside a directory the web server executes becomes remote code execution. Safe storage removes that opportunity: store files where they cannot be executed, and serve them in a way that guarantees they are treated as inert data, not code.

Two related ideas support this: keeping uploads outside the webroot (the directory tree the web server will happily run or serve as application code), and applying isolation so uploaded content lives apart from application code and from other users' files.

How it works

  • Store outside the webroot. Place uploaded files in a directory the web server does not map to executable request handling — or, better, in a dedicated object/blob store separate from the application server. If the files are not in a place the server will execute, a disguised script cannot run even if it slipped through.
  • Serve as inert content. When you hand a stored file back to a user, do it through code that streams the bytes with a safe, fixed response: a non-executable content type, a Content-Disposition that encourages download rather than inline interpretation where appropriate, and headers that prevent the browser from guessing the type. This stops a stored file from being rendered as HTML or script in a victim's browser.
  • Separate the serving domain or path. Serving user uploads from a different origin or a dedicated, restricted path limits what a malicious file could do even if it were interpreted, because it is isolated from the application's trusted origin and cookies.
  • Apply least privilege to the storage. The account or service that writes uploads should not have execute permission on that location, and the directory should not allow scripts to run. This applies the least-privilege principle to the upload directory itself.
  • Keep names and paths under application control. Combined with the safe filenames from the previous lesson, the application — not the user — decides the exact storage path, preventing traversal into sensitive locations.

Practical example

In an isolated practice setup, a training app saves uploads into a folder inside its own web-served directory and lets the server handle requests to that folder normally. A learner uploads a small server-side script disguised as an image; because the folder is inside the executable webroot, requesting the file runs it — a contained demonstration of the worst case.

The hardened lab app stores the same upload in a separate location outside the webroot (or in an object store) and serves it only through a handler that returns the bytes with a fixed non-executable content type and a download disposition. Requesting the file now downloads inert bytes instead of executing anything. The learner directly observes how the storage location and serving method — not just validation — decided whether the file was dangerous.

[!WARNING] Only reproduce upload-execution scenarios inside environments you own or are explicitly authorized to test, kept isolated from real systems and the internet. The purpose is to learn safe storage, not to attack live services.

Cybersecurity relevance

Storage decisions are frequently the difference between a harmless accepted file and a serious compromise. Many real incidents come down to an uploaded file being written somewhere the server would execute or render it. Storing outside the webroot, serving files as inert downloads, isolating the serving origin, and removing execute permission are standard, high-value defenses. They also embody defense in depth: even if validation has a gap, safe storage ensures an accepted file cannot be run. For authorized testers, checking where uploads land and how they are served is a key step in assessing an upload feature.

Common mistakes

  • Saving uploads inside the executable webroot, so a slipped-through script can be run.
  • Serving user files inline with a guessable content type, letting the browser render them as HTML or script.
  • Serving uploads from the application's own trusted origin with no isolation.
  • Granting execute permission on the upload directory or over-privileging the storage account.

Key takeaways

  • A malicious file is only dangerous when interpreted or executed; the storage location controls that.
  • Store uploads outside the webroot (or in a separate object store) so they cannot be executed.
  • Serve files as inert data with a fixed non-executable type, download disposition, and no type-sniffing.
  • Isolate the serving origin and apply least privilege; keep storage paths under application control.

Check your understanding

  • Why does storing an uploaded file outside the webroot prevent a disguised script from executing?
  • What serving practices ensure a stored file is treated as inert data rather than active content?
FINISH THIS LESSON

Sign in to save your progress.