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