# MIME Detection Security Assessment > **Note (v1.5.1):** Magic byte detection has been simplified to UTF-8 validation only. > Content is now classified as `text/plain` (valid UTF-8) or `application/octet-stream` (binary). > Security headers (nosniff, CSP) provide the primary defense against MIME confusion attacks. > This document is retained for historical reference. Penetration testing of FlaskPaste's magic byte-based MIME detection system. --- ## Executive Summary **Assessment Date:** 2025-12-25 **Target:** FlaskPaste MIME detection (`app/api/routes.py`) **Methodology:** Polyglot file attacks, magic byte spoofing, header injection **Result:** No critical vulnerabilities found. Defense-in-depth approach effective. --- ## Attack Surface ### MIME Detection Implementation ```python # Location: app/api/routes.py MAX_MAGIC_LEN = 16 # Maximum bytes checked for magic signatures MAGIC_SIGNATURES = { b"\x89PNG\r\n\x1a\n": "image/png", b"\xff\xd8\xff": "image/jpeg", b"GIF87a": "image/gif", b"GIF89a": "image/gif", # ... 42 total signatures } ``` Detection checks first 16 bytes against known magic byte patterns. --- ## Testing Methodology ### Tools Used - `fpaste` CLI client (with PoW solving) - `curl` for raw HTTP requests - `xxd` for binary file creation - Python scripts for complex payloads ### Test Categories 1. Standard MIME detection validation 2. Polyglot file attacks 3. Magic byte boundary conditions 4. Header injection attempts 5. Security header verification --- ## Test Results ### Phase 1: Standard MIME Detection | Format | Magic Bytes | Detected MIME | Status | |--------|-------------|---------------|--------| | PNG | `89 50 4E 47` | image/png | PASS | | JPEG | `FF D8 FF E0` | image/jpeg | PASS | | GIF | `47 49 46 38 39 61` | image/gif | PASS | | PDF | `25 50 44 46` | application/pdf | PASS | | ZIP | `50 4B 03 04` | application/zip | PASS | | GZIP | `1F 8B 08` | application/gzip | PASS | | SQLite | `53 51 4C 69 74 65` | application/x-sqlite3 | PASS | | ELF | `7F 45 4C 46` | application/x-executable | PASS | | PE/EXE | `4D 5A` | application/x-msdownload | PASS | ### Phase 2: Polyglot File Attacks #### Test 1: PNG + HTML Payload ```bash # Payload: PNG magic bytes + HTML after detection window echo -e '\x89PNG\r\n\x1a\n\x00\x00\x00\x00' > poly.bin ``` **Result:** - Detected MIME: `image/png` (first magic wins) - Served Content-Type: `image/png` - **SAFE:** HTML payload ignored, served as image #### Test 2: SVG with Embedded JavaScript ```xml ``` **Result:** - Detected MIME: `text/plain` (no XML magic in signatures) - Served Content-Type: `text/plain; charset=utf-8` - **SAFE:** Not served as SVG, scripts won't execute #### Test 3: GIF89a JavaScript Polyglot ``` GIF89a/**/=1;alert(1)// ``` **Result:** - Detected MIME: `image/gif` - Served Content-Type: `image/gif` - **SAFE:** Even if loaded as `' > poly.bin # SVG with script cat > poly.svg << 'EOF' EOF # GIF+JS polyglot echo 'GIF89a/**/=1;alert(1)//' > poly.gif # JPEG+PHP echo -e '\xff\xd8\xff\xe0\x00\x10JFIF\x00' > poly.jpg ``` ### Upload and Verify ```bash # Upload with fpaste id=$(./fpaste -s https://mymx.me/paste create -E -q poly.bin) # Check detected MIME curl -s "https://mymx.me/paste/$id?info" | jq .mime_type # Verify served headers curl -sI "https://mymx.me/paste/$id/raw" | grep -i content-type ``` --- ## Recommendations ### Current Implementation: SECURE The current implementation provides adequate protection through: 1. **Deterministic detection:** First matching magic bytes determine MIME type 2. **Safe defaults:** Unknown content served as `application/octet-stream` or `text/plain` 3. **Strong CSP:** `default-src 'none'` prevents script execution 4. **No sniffing:** `X-Content-Type-Options: nosniff` honored by browsers 5. **No processing:** Content stored and served as-is, never executed ### Potential Enhancements (Low Priority) 1. **Add SVG detection** with forced `text/plain` serving (prevents accidental SVG execution in older browsers) 2. **Content-Disposition: attachment** for all downloads (forces download instead of inline display) 3. **Sandbox iframe serving** for HTML-like content (additional isolation layer) --- ## Conclusion The FlaskPaste MIME detection system is resistant to polyglot file attacks due to: - Deterministic magic byte matching (first match wins) - Strong security headers preventing browser-side exploitation - No server-side content interpretation or execution - Safe fallback to `text/plain` or `application/octet-stream` **Risk Level: LOW** The attack surface is minimal because detected MIME types only affect the `Content-Type` header served to clients, and browser-side exploitation is blocked by CSP and X-Content-Type-Options headers. --- ## Automated Fuzzing Results ### Fuzzer Execution ```bash ./venv/bin/python tests/fuzz/run_fuzz.py --verbose ``` ### Summary | Metric | Value | |--------|-------| | Total phases | 6 | | Total requests | 192 | | CRITICAL findings | 3 (expected behavior) | | HIGH findings | 10 (false positives) | | MEDIUM findings | 1 (intentional) | ### Finding Analysis | Finding | Verdict | Reason | |---------|---------|--------| | X-SSL-Client-SHA1 bypass | EXPECTED | No TRUSTED_PROXY_SECRET configured in test | | Header injection (10x) | FALSE POSITIVE | Werkzeug sanitizes; payloads not reflected | | /metrics exposed | INTENTIONAL | Required for Prometheus monitoring | ### Verification Header injection claims verified as false positives: ```bash # Host header not reflected curl -sI http://127.0.0.1:5099/ -H "Host: evil.com" | grep evil # (no output) # SQL payload not reflected curl -s http://127.0.0.1:5099/ -H "X-Forwarded-For: ' OR 1=1--" | grep "OR 1=1" # (no output) # CRLF injection blocked by Werkzeug curl -sI http://127.0.0.1:5099/ -H "Host: evil.com X-Injected: true" | grep X-Injected # (no output) ``` **Conclusion:** The fuzzer correctly identified expected behaviors but produced false positives for header injection attacks. Flask/Werkzeug properly sanitizes all header inputs.