| name | s3-minio-content-type-xss |
| description | Exploit public bucket Content-Type override for stored XSS on target origin. |
| version | 1.1.0 |
| revision_date | "2026-07-25T00:00:00.000Z" |
| license | MIT |
| platforms | ["linux"] |
| compatibility | Requires curl, python3 |
| tags | ["recon","S3","MinIO","bucket","XSS","Content-Type","cloud","storage"] |
| category | recon |
| related_skills | ["hunt-xss","hunt-cloud-misconfig","firebase-supabase-attack","js-secrets-extraction"] |
S3/MinIO Content-Type Override to Stored XSS
Exploit public cloud storage buckets (S3, MinIO, and compatible) by overriding the Content-Type response header via query parameters. When a target serves user-uploaded files from its own origin (e.g., cdn.target.com or target.com/uploads/), a successful override turns a stored HTML/JS payload into same-origin stored XSS — bypassing every upload-time validation the application performed.
When to Use
- Target serves user-uploaded files (images, avatars, attachments) from a public bucket.
- Files are served under the target's own domain or subdomain (not a random storage domain).
- Upload validation appears solid (extension whitelist, magic byte check, forced Content-Type) — the override bypasses all of these at serve time, not upload time.
- The bucket URL responds to
?response-content-type= with a changed Content-Type.
- The bucket returns an AWS SignatureDoesNotMatch error leaking the real bucket host and region.
Prerequisites
terminal with curl and python3.
- Identify at least one public object URL served from storage.
- For S3 exploitation: your own AWS account credentials (free tier sufficient).
Quick Detection
curl --max-time 30 --connect-timeout 10 -skI "https://cdn.target.com/uploads/avatar123.png?response-content-type=text/html" | grep -i content-type
Procedure
Phase 1 — Identify Public Objects
Find uploaded objects served publicly:
for path in /uploads/ /media/ /static/uploads/ /cdn/ /files/ /assets/img/ /storage/; do
curl --max-time 30 --connect-timeout 10 -skI "https://target.com${path}" | grep -E "HTTP|Content-Type|x-amz"
done
curl --max-time 30 --connect-timeout 10 -sk | grep -Eo \'