hunt-cors – Other skill for AI agents
Hunt CORS Misconfiguration
Install the hunt-cors 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/hunt-cors-a1d44.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /hunt-cors – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-cors-a1d44.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $hunt-cors – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-cors-a1d44.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /hunt-cors – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-cors-a1d44.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /hunt-cors – then describe the task you want done.
SKILL.md content
> ⚠️ AUTHORIZED USE ONLY
> This skill is for educational purposes or authorized security assessments only.
> You must have explicit, written permission from the system owner before using this tool.
> Misuse of this tool is illegal and strictly prohibited.
> Mandatory confirmation gate
> Before running any command that probes, exploits, changes, persists on, extracts data from, or attempts credential access against a target:
> 1. Ask the user to state the exact target URL, IP, account, or resource.
> 2. Ask the user to confirm written authorization and the permitted scope.
> 3. Show the exact command(s) and explain their expected effect.
> 4. Wait for explicit confirmation in the current conversation.
>
> Without that confirmation, remain read-only and provide defensive guidance only. Prefer a sandbox, disposable VM, or controlled lab.
HUNT-CORS — Cross-Origin Resource Sharing Misconfiguration
What actually pays (and what does not)
Credentialed cross-origin data disclosure is established only when an attacker-controlled origin can perform a
credentialed cross-origin read of sensitive authenticated data, and you
have a browser PoC proving the response body is readable from evil.com.
Two hard browser rules that kill most "findings" — check these FIRST:
- **
Access-Control-Allow-Origin: *CANNOT be combined with credentials.**
If the server returns ACAO: *, the browser refuses to expose the
response for a credentials: include request; a simple request may still have been sent, so this is not CSRF protection. A wildcard-only endpoint is
not credential-exploitable. It is only interesting if the data it serves
is sensitive *without* a session (rare) — usually this is Informational/Low.
Access-Control-Allow-Credentials: trueis meaningless on its own. It
matters only if ACAO reflects/allows your specific attacker origin AND a
cross-origin credentialed fetch actually returns a readable body. ACAC on a
response that does not reflect your origin proves nothing.
For a credentialed-read claim, prove browser-readable protected data under the actual cookie/browser conditions. Header differences alone do not establish impact; severity follows the application and program, not this guide.
---
Crown Jewel Targets
- Reflect-any-origin + credentials — server echoes the
Originheader AND
sets ACAC: true → any site reads authed API responses. The classic High.
- Null-origin trust —
ACAO: null+ACAC: true. Asandboxiframe (or a
data:/redirect chain) emits Origin: null, so a controlled opaque-origin document may read data if cookies and all browser checks permit it.
- Subdomain-regex bypass — trusted-origin regex with a parsing flaw. The
correct payload depends on *which* flaw (see Phase 3 — this is where most
skills get it wrong).
- Subdomain takeover → trusted origin — a dangling subdomain that the CORS
policy trusts; take it over, host the PoC there (see hunt-subdomain).
- postMessage missing/loose origin check — handler that processes
event.data without strictly validating event.origin.
---
Attack Surface Signals
Any endpoint returning an Access-Control-Allow-Origin header
API endpoints: /api/*, /v1/*, /graphql
Profile/account: /api/me, /api/profile, /api/user, /api/session
Secrets/tokens: /api/tokens, /api/keys, /api/csrf, /api/account/settings
Financial: /api/balance, /api/transactions
Admin/internal: /api/admin/*, /api/internal/*Prioritize endpoints that (a) require a session cookie and (b) return PII,
tokens, CSRF tokens, or other secrets in the body.
---
Step-by-Step Hunting Methodology
After the exact-command gate, use only owner-approved URLs/accounts and origins you control. Validate bulk input against the scope allowlist before adding any credential. CURL_AUTH_CONFIG is an existing private untracked curl config containing only the test account’s cookie; do not put it in argv, logs or reports. Do not follow redirects with account cookies across an unreviewed destination. Header probes are hypotheses, not browser evidence.
Phase 1 — Discover CORS endpoints
# Probe API endpoints. Use GET (not -I): some servers only emit CORS on GET,
# and -I sends HEAD which may be handled differently.
while IFS= read -r url; do
result=$(curl -s -D - -o /dev/null "$url" \
-H "Origin: https://evil.com" \
--config "$CURL_AUTH_CONFIG" | grep -i "access-control")
[ -n "$result" ] && echo "=== $url ===" && echo "$result"
done < "recon/$TARGET/api-endpoints.txt"
# httpx bulk check
cat recon/$TARGET/live-hosts.txt | awk '{print $1}' | \
httpx -H "Origin: https://evil.com" -match-string "access-control-allow-origin"Phase 2 — Reflect-any-origin + null origin
# Does the server reflect an arbitrary Origin back?
curl -s -D - -o /dev/null https://$TARGET/api/me \
-H "Origin: https://evil.com" \
--config "$CURL_AUTH_CONFIG" | grep -i "access-control"
# Vulnerable (the High case):
# Access-Control-Allow-Origin: https://evil.com <- reflects attacker origin
# Access-Control-Allow-Credentials: true <- + credentials => readable
#
# NOT exploitable for credentialed theft:
# Access-Control-Allow-Origin: * <- browser blocks creds read
# (no ACAC, or ACAC absent) <- not credentialed
# Null-origin trust
curl -s -D - -o /dev/null https://$TARGET/api/me \
-H "Origin: null" \
--config "$CURL_AUTH_CONFIG" | grep -i "access-control"
# Looking for: Access-Control-Allow-Origin: null + ACAC: truePhase 3 — Subdomain / trusted-origin regex bypass
The right payload depends on which regex flaw the server has. Identify the
class first, then send the matching payload. Getting this wrong wastes the test
and produces false negatives.
| Server regex (intended: trust *.target.com) | Flaw | Bypass origin that matches | Why |
|---|---|---|---|
| ^https?://.*\.target\.com$ | None — escaped dot + end-anchor. Correct. | (no simple bypass) | evil.target.com is in-scope by design; x.target.com.evil.com ENDS in .evil.com, fails $. Move on or look for subdomain-takeover. |
| ^https?://.*target\.com$ | Missing dot separator (no \. before target) | https://eviltarget.com | .*target\.com$ matches eviltarget.com — attacker registers eviltarget.com. |
| ^https?://.*\.target\.com | Missing end-anchor $ | https://x.target.com.evil.com | regex matches a prefix; .target.com appears, then .evil.com is ignored (no $). |
| ^https?://target\.com | Prefix-only, no $ | https://target.com.evil.com | matches the target.com prefix; the rest is unconstrained. |
| ^https?://.*\.target\.com$ but dot in regex is unescaped (.*.target.com$) | Unescaped dot = "any char" | https://xtargetXcom... style, or https://evilZtargetZcom where Z is any single char | . matches any character, widening the match. |
| Any of the above | Special chars browsers send in Origin | https://target.com%60.evil.com, https://target.com\x60evil.com | some parsers treat backtick/underscore as letters; Safari/older browsers may emit unusual origins. Confirm the browser actually sends it. |
# Send each class-specific payload and watch what the server reflects.
for ORIGIN in \
"https://evil.target.com" \
"https://eviltarget.com" \
"https://x.target.com.evil.com" \
"https://target.com.evil.com" \
"https://target.com%60.evil.com" \
"http://target.com"; do
RESULT=$(curl -s -D - -o /dev/null "https://$TARGET/api/me" \
-H "Origin: $ORIGIN" \
--config "$CURL_AUTH_CONFIG" | grep -i "access-control")
echo "[$ORIGIN] -> ${RESULT:-no CORS}"
doneA bypass is real only if the server reflects your registerable origin into
ACAO with ACAC: true. evil.target.com reflecting back is NOT a bug unless
you can actually control a *.target.com host (then see Phase 6 / hunt-subdomain).
Phase 3b — Trusted insecure (HTTP) origin
If ACAO reflects/allows any http:// origin (even a correctly-anchored in-scope one) with ACAC:true, a network attacker on that cleartext host injects a page that reads the authed cross-origin body — no regex flaw needed, the plaintext scheme IS the flaw.
curl -s -D- -o/dev/null "https://$TARGET/api/me" -H "Origin: http://sub.$TARGET" --config "$CURL_AUTH_CONFIG" | grep -i access-controlReal only if a MITM can occupy that http origin (no HSTS-preload). Pair with hunt-tls-network. (PortSwigger: CORS with trusted insecure protocols.)
Phase 4 — Pre-flight (OPTIONS) gating bypass
Non-simple requests (custom headers, PUT/DELETE/PATCH, non-simple
Content-Type) trigger a CORS pre-flight OPTIONS. The browser only sends
the real request if the pre-flight response authorizes the method/header. Two
things to test:
1. Does the pre-flight authorize arbitrary methods/headers for your origin?
If `Access-Control-
… (full content is in the download package)
Related skills
- hunt-deserialization – Hunt Insecure Deserialization
- hunt-exceptional-conditions – Hunt mishandling of exceptional conditions
- hunt-file-upload – Hunt file upload bugs
- hunt-forgot-password – Hunt Forgot Password / Account Recovery Authentication Flaws
- hunt-host-header – Hunt Host Header Injection
- hunt-html-injection – Hunt HTML Injection
- hunt-http-smuggling – Hunt HTTP request smuggling (CL.TE, TE.CL, H2.CL, H2.TE).
- hunt-jwt-crypto – Hunt JWT cryptographic failures