# Bypassing File Upload Restrictions To Exploit Client-Side Path Traversal

Crafting JSON files that also satisfy PDF/WEBP magic-byte and parser checks bypasses upload validation, enabling CSPT2CSRF gadgets.

- Payout: Research
- Program: File upload validation
- Credited: Doyensec
- Disclosed: 2025-01-08
- Write-up quality: 7/10
- Original: https://blog.doyensec.com/2025/01/09/cspt-file-upload.html
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2025-01-09-cspt-file-upload-html
- Tags: domain:web impact:integrity kind:research platform:research technique:parser-differential technique:source-review vuln:csrf vuln:file-upload vuln:path-traversal

**Target:** File upload validation libraries (mmmagic, pdflib, file command, file-type)
**Root cause:** Validators check magic bytes at fixed offsets or parse only a prefix, while browsers parse the whole file as JSON; the two parsers disagree on file type.
**Steps:**
1. mmmagic: place `%PDF` inside a JSON key within first 1024 bytes: `{ "id" : "../CSPT_PAYLOAD", "%PDF": "1.4" }`
2. pdflib: embed a full PDF object stream as a JSON string value, replacing LF with spaces so it stays valid JSON
3. file command: pad JSON with >1MB whitespace so file_is_json fails and it falls back to PDF magic detection
4. file-type: place `WEBP` at offset 8: `{"aaa":"WEBP","_id":"../../../../CSPT?"}`
5. Upload crafted file; client JSON.parse yields path-traversal `_id` used in fetch for CSPT2CSRF
**How found:** Reading third-party validator source (mmmagic magic rules, file-type offset checks, file command byte limit) and comparing their parsing model against browser JSON.parse to find discrepancies.
**Exploitation:** Upload a file that passes server-side type validation but is parsed as JSON client-side; the JSON `_id`/path field contains `../../` traversal to redirect a same-origin fetch to an attacker-chosen endpoint, achieving CSRF or XSS.
**Escalation:** Chains upload bypass with CSPT2CSRF, JSONP gadget, or open redirect to escalate to XSS/CSRF.
**Insight:** When a server validates file type but the client JSON.parses the same bytes, hunt for parser differentials: magic bytes allowed at non-zero offsets, prefix-only parsing, or size limits that force fallback detection.
