diff --git a/documentation/mime-security-assessment.md b/documentation/mime-security-assessment.md new file mode 100644 index 0000000..0036e54 --- /dev/null +++ b/documentation/mime-security-assessment.md @@ -0,0 +1,241 @@ +# MIME Detection Security Assessment + +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.