Course / 09 Web security / Lesson 08 of 28

File upload

Estimated time: 16 min reading · 12 min activity

An uploaded file crosses from a caller's device into storage the application controls. Its filename and declared media type, such as image/jpeg, are claims supplied with the upload. A media type describes a format; it does not prove that the submitted bytes form a valid file of that format.

A file signature is a recognizable byte sequence associated with a format. It can support a hypothesis, but a complete valid image also needs the rest of its required structure. The supplied eight-byte fixture deliberately contains only a signature. No image parser has confirmed a complete image.

Before you begin

Estimated time
16 min reading, 12 min activity. Setup and optional practice may take longer.
Where you work
Read the original fictional requests, source fragments and state tables in a current desktop or mobile browser. The required activity needs no server, database, account or installed security tool. Do not send the printed requests to any service.
Without a lab
Use the complete printed evidence to trace the data or state on paper. Write the decision, the fact supporting it and one limit of the model, then compare with the activity rubric. This does not establish live service behavior. Reading works without JavaScript. Checking requires JavaScript and a secure browser context; saving also requires usable browser storage.

After this lesson you can:

  • Separate a filename, a declared media type, and the bytes.
  • Read the activity bytes 64 65 73 6B as letters.
  • Pick the storage card that keeps an upload out of the executed directory.

01Example

The fictional file note.jpg claims image/jpeg, but its five bytes are ordinary text. Use ASCII to interpret the evidence before trusting the name.

Claimed name: note.jpg
Claimed media type: image/jpeg
Bytes: 68 65 6C 6C 6F
Text interpretation: hello
The claim does not match the contents.

02Claims, bytes, and a place to put them

The worked bytes spell hello, even though the filename claims an image. The guided activity uses different text bytes. Compare the claim with the actual byte evidence before judging storage policies. The checkpoint supplies a separate signature-only file; name the format suggested by that evidence, without claiming the whole file is valid.

Upload handling needs several controls: allow only required types, validate content with appropriate tooling, limit size and decompression work, and keep uploads outside executable application paths. S1 addresses the execution boundary in this model. Type validation and safe storage have different jobs; neither filename nor declared type is enough.

Compare a filename and a declared type with the bytes, and store an upload outside the directory the server runs as code.Model. A teaching model drawn by hand. It shows the idea, not real tool output.

Read the full explanation below.

Playback is optional. Step through at your own pace.

Supplied teaching sample

Supplied upload claims

note.jpgfilename claim
image/jpegmedia claim

Supplied bytes

68 65 6C 6C 6Ffive bytesThese five bytes are supplied; no image decoder ran.

Text interpretation

helloASCII reading

note.jpg + image/jpeg → 68 65 6C 6C 6FClaims differ from contents

Filename and media type are caller claims.

Follow the explanation

  1. Filename and media type are caller claims.
  2. The supplied bytes read hello, which does not establish a JPEG.
Read every state and value

1. Filename and media type are caller claims.

Example
Supplied teaching sample
Visible Item
note.jpg · image/jpeg · 68 65 6C 6C 6F
Current mappings
Claims differ from contents
Annotations
Item: 68 65 6C 6C 6F; Text: These five bytes are supplied; no image decoder ran.

2. The supplied bytes read hello, which does not establish a JPEG.

Example
Supplied teaching sample
Visible Item
note.jpg · image/jpeg · 68 65 6C 6C 6F · hello
Current mappings
Supplied ASCII interpretation · Claims differ from contents
Annotations
None
Names and declared media types are claims; byte validation and safe storage have separate jobs.

03Read the activity bytes

Read the evidence before comparing your reasoning with the activity rubric. Do not run an image parser.

PNG signature from the PNG specification, section 5.2, eight bytes:
89 50 4E 47 0D 0A 1A 0A

benign-mislabeled.jpg contains only those eight bytes.
It has no IHDR chunk and no IEND chunk, so it is not a complete PNG datastream.
No image parser was run. The filename and the declared type are claims.

Worked card
filename: note.jpg
declared: image/jpeg
bytes: 68 65 6C 6C 6F
ASCII from Stage 04: hello
The bytes are letters.

Activity card
filename: badge.jpg
declared: image/jpeg
bytes: 64 65 73 6B
ASCII: desk
The bytes are letters.

Field card
filename: image.jpg
declared: image/jpeg
bytes: 89 50 4E 47 0D 0A 1A 0A
Compare these bytes with the reference signature and state what format they suggest. A signature match alone does not establish a complete valid image.

Download the byte table

Upload storage cards. Pick the card that matches the stated goal.

S1 Store the bytes outside the directory that the server executes as code.
S2 Trust the filename suffix and store the file beside the application.
S3 Trust the declared media type and display the file as that type.

The goal in this lesson is to keep an upload from becoming a program the server runs.
S1 matches that goal. S2 and S3 trust a claim.

Download the storage cards

  1. Read the activity card. Write the filename, the declared type, and the bytes.
  2. Use the Stage 04 reading of those bytes.
  3. Check: the bytes are the letters desk. They are not the eight-byte signature. S1 is the storage card that matches the goal. The worked bytes are hello.
  4. Stop. Do not upload this file to a real application.

04Optional challenge

Say why S1 matches the goal and S2 does not. The rubric is: S1 moves the bytes out of the executed directory, and S2 trusts the suffix. About ten minutes.

05Fresh cases for the checks

Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.

Upload case A: signature comparison, no parser runOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

PNG reference signature: 89 50 4E 47 0D 0A 1A 0A.
Candidate filename: letter.txt; declared media type: text/plain.
Candidate bytes: 89 50 4E 47 0D 0A 1A 0A, and nothing else.
No image chunks or parser result are supplied.

Upload case B: independent text bytesOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

Filename: sketch.jpg; declared type: image/jpeg.
Bytes: 6F 61 6B
Supplied ASCII map: 6F=o, 61=a, 6B=k.
These are all the bytes; no decoder or parser is run.

06Explain your evidence

Optional written self-check: explain one decision using the supplied case. No tool run is required.

Check your explanation: compare claims with supplied bytes; distinguish a matching signature from a complete parser-accepted file; trace the ASCII map; connect upload storage to the server execution boundary.

07Common mistakes

If you call the activity bytes an image because the name ends in jpg, you trusted the claim. The bytes are letters.

If you call the eight-byte file a complete image, you skipped the missing IHDR and IEND. The signature is only the first eight bytes of a datastream.

If you pick S3 because the declared type says image, you trusted the claim the card warns about.

References

  • PNG Specification (Third Edition), section 5.2

    W3C Recommendation of 24 June 2025, read. The first eight bytes are 89 50 4E 47 0D 0A 1A 0A. The signature indicates that the remainder is a single PNG image of chunks from IHDR to IEND. The fixture is only those eight bytes, so it is not a complete PNG.

  • PortSwigger: File upload

    Explains the failure mechanism and prevention. Use it for further reading after reasoning from this page's original model; a topic page is not evidence that a lab was launched.