M_07/ A04:2021 — Insecure Design

Insecure File Upload

Drag a file in (or pick a sample). The simulator runs each validation layer in turn and shows what happens when one is missing.

1.0 Upload Zone
Drag a file here
(or pick a sample below)
2.0 Server-side validation pipeline
Filename ends in image extension
shell.php.jpg
Declared Content-Type is image/*
image/jpeg
Magic bytes match an image format
3C 3F 70 68 70
Declared MIME matches real MIME
image/jpeg vs text/x-php
Final write
→ /var/www/uploads/shell.php.jpg
→ attacker requests: GET /uploads/shell.php.jpg
→ Apache executes as PHP → webshell live
Vulnerable
if (file.name.endsWith('.jpg'))
  fs.rename(tmp, '/uploads/' + file.name);
Secure
const mime = await fileTypeFromBuffer(buf);
if (!ALLOW.has(mime?.mime)) throw 415;
const name = randomUUID() + '.' + mime.ext;
await writeFile(STORAGE_OFF_WEBROOT + name, buf);
3.0 Intelligence

What just happened

At least one validation layer failed. A typical stack still writes the file to the web root, where the OS or web server can execute it.

Logical flow

  • 01Attacker crafts a polyglot or double-extension file.
  • 02Upload endpoint only checks the easiest layer (filename suffix).
  • 03File lands in /uploads/ inside the web root.
  • 04Attacker requests the file → web server executes it as code.
  • 05Webshell gives interactive RCE on the host.
Risk
Critical
OWASP
A04
Webshell deployed
↳ What the developer intended
Users upload profile pictures; non-image files are rejected.
↳ What the runtime actually executes
Suffix-only check is bypassed by double extensions / MIME spoofing.
Webshell ends up under /uploads where the web server executes it.
Attack flow