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

file handling

File Upload · CTF

Freereading · 10 min
On this page
LESSON

Overview

Once an upload passes the front-door checks, the application still has to handle the file: figure out what it really is, give it a safe name, and process it without letting its contents cause harm. This lesson focuses on the mechanics of safe file handling — especially the difference between the file's declared type and its actual type, and how to derive a safe filename. These techniques are studied here only in authorized, isolated practice so you can build features that are hard to abuse.

Learning objectives

  • Contrast the declared Content-Type with the file's real content signature.
  • Explain how magic bytes reveal a file's true type.
  • Generate safe filenames that resist path and interpretation tricks.

Core concept

A file has two "identities": what the client claims it is (the Content-Type header and the extension) and what it actually is (the bytes inside it). Safe handling means resolving the real identity from the bytes, not the claim, and then treating the file conservatively based on that reality.

The most reliable content signal is the file's magic bytes: a short, well-known byte sequence at the start of a file that identifies its format. For example, PNG files begin with a fixed 8-byte signature and JPEG files begin with their own marker bytes. These signatures are part of the file format itself, so checking them tells you what a file genuinely is — something a header cannot do.

The other half of safe handling is the filename. The name the user supplies can contain path separators, .. sequences, null bytes, control characters, or a misleading extension. The application should never use that raw name to decide where the file goes or how it is interpreted.

How it works

  • Read the magic bytes. Inspect the leading bytes of the uploaded file and compare them against the signatures of the formats you allow. If the bytes do not match an allowed format, reject the file — even if the header and extension looked fine. This is the content-type-vs-magic-bytes check in practice.
  • Do not rely on magic bytes alone for "safe rendering." Confirming a file is a real PNG stops disguised scripts, but some formats can still carry active content (for example, certain image or document formats). Combine content verification with safe storage and serving (later lesson) — for instance, serving user files with a fixed, non-executable content type.
  • Generate a safe filename. Instead of keeping the user's name, assign your own: strip the path to keep only the base name, allow only a known-safe character set, and often replace the stored name entirely with a random identifier (for example, a generated token) while keeping the validated extension. This removes path-traversal characters and prevents the name itself from influencing how the file is treated.
  • Normalize the extension from the verified type. Once you know the real type from the magic bytes, set the extension yourself rather than trusting the uploaded one, so a .png file is truly a PNG.

Practical example

In a personal lab, a training app lets you upload images and previously stored them under the exact name the client sent. A learner uploads a file whose name contains directory-traversal characters and a deceptive double extension. Because the app used the raw name, the file lands somewhere unintended — a clear, contained demonstration of why raw filenames are dangerous.

The hardened version of the lab app handles the same upload safely: it reads the leading bytes and confirms they match the PNG signature, rejects the file if they do not, discards the client-supplied name, and stores the file as a freshly generated random identifier with a .png extension it assigns itself. The traversal characters never reach the filesystem path, and a disguised non-image is refused outright. The learner can compare both behaviors side by side in isolation.

Cybersecurity relevance

Weak file handling is what turns an accepted upload into a real problem. Trusting the declared type lets disguised files slip through; trusting the client's filename opens the door to path traversal and to files being interpreted in unintended ways. Verifying content via magic bytes and assigning safe, application-controlled filenames are core defensive techniques used across real applications. For authorized testers, checking whether an app verifies content and how it names stored files is a routine part of evaluating an upload feature. The underlying lesson generalizes: derive facts from the data itself, and never let untrusted input dictate names, paths, or interpretation.

Common mistakes

  • Treating the Content-Type header as the file's true type instead of checking magic bytes.
  • Storing files under the user-supplied name, carrying path-traversal characters and misleading extensions.
  • Assuming a valid magic-byte check makes a file completely safe, ignoring safe storage and serving.
  • Keeping the client's extension rather than assigning one from the verified content type.

Key takeaways

  • A file's declared type is a claim; its magic bytes reveal what it actually is.
  • Verify content against the signatures of allowed formats, and reject mismatches.
  • Never trust the client's filename: strip paths, restrict characters, and prefer application-generated names.
  • Assign the extension from the verified type, and pair content checks with safe storage and serving.

Check your understanding

  • How do magic bytes let you determine a file's real type when the Content-Type header cannot?
  • Why should an application generate its own filename rather than store the one the client supplied?
FINISH THIS LESSON

Sign in to save your progress.