{"id":"hunt-auth-bypass","name":"hunt-auth-bypass","summary":"認証回避の脆弱性を探すスキルを探しています。SAML XSW / パーサー差分(GitHub Enterprise CVE-2025-25291/25292)、SAML署名ストリッピング(Uber、Rocket.Chat、samlify CVE-2025-47949)、制御文字によるSAMLドメイン強制バイパス(Ha…","body":"## Crown Jewel Targets\n\nAuth bypass is consistently one of the highest-paying vulnerability classes in bug bounty because it directly violates the most fundamental security control. High-value targets include:\n\n- **SSO/SAML implementations** at enterprise SaaS companies (Slack, Okta, OneLogin integrations) — payouts regularly in the $5K–$25K+ range\n- **Admin panels and partner/internal portals** — subdomain-separated admin surfaces like `partners.shopify.com`, `admin.company.com`\n- **Third-party auth plugin integrations** — WordPress plugins (OneLogin, WP-SAML-Auth), Drupal SSO modules, any CMS with pluggable auth\n- **XMLRPC endpoints** on WordPress — often forgotten, bypasses standard WP auth flows entirely\n- **OAuth callback flows** — state parameter mishandling, redirect_uri mismatches\n- **API authentication layers** — especially where auth was bolted on after the fact\n\n**Asset priority:** Targets with federated identity (SAML, OAuth, OIDC) connected to large user populations. Partner/reseller portals are particularly juicy because they often have elevated permissions and less security scrutiny than the main product.\n\n---\n\n## Attack Surface Signals\n\n**URL patterns to hunt:**\n```\n/xmlrpc.php\n/wp-login.php\n/saml/\n/sso/\n/auth/saml/callback\n/oauth/callback\n/partners.*\n/admin.*\n/?wc-api=\n/api/v*/auth\n/login?redirect=\n/accounts/login\n```\n\n**Response headers signaling SSO:**\n```\nX-Frame-Options: SAMEORIGIN (common on SSO portals)\nSet-Cookie: SAMLResponse=\nLocation: https://idp.company.com/saml\nWWW-Authenticate: Bearer realm=\"partners\"\n```\n\n**JS patterns indicating federated auth:**\n```javascript\n// Look for in page source\nsamlRequest\nRelayState\nSAMLResponse\nonelogin\nshibboleth\nokta\npassport.js authenticate\n```\n\n**Tech stack signals:**\n- WordPress + any SSO plugin → check XMLRPC separately\n- Shopify Partner API exposure → cross-tenant privilege escalation risk\n- Any app advertising \"SSO enabled\" or \"Login with [Enterprise IdP]\"\n- Separate subdomains for admin/partner that share session cookies with main domain\n- Applications using `SimpleSAMLphp`, `ruby-saml`, `python-saml`\n\n**Burp passive scan triggers:**\n- `SAMLResponse` in any POST body\n- `openid_connect` or `id_token` in responses\n- Cookie domains set to `.company.com` (wildcard)\n\n---\n\n## Step-by-Step Hunting Methodology\n\n1. **Map all authentication entry points**\n   - spider the target for every login surface: main login, admin login, API login, partner portal, mobile API endpoints\n   - check `robots.txt`, JS files, and the wayback machine for forgotten endpoints like `/xmlrpc.php`\n\n2. **Identify the auth mechanism per entry point**\n   - Is it forms-based, SAML, OAuth, API key, session token?\n   - For WordPress: always probe `/xmlrpc.php` even if the main login is SSO-protected\n\n3. **Test XMLRPC independently of SSO**\n   - If site uses SSO (e.g., OneLogin), manually POST to `/xmlrpc.php`\n   - XMLRPC uses WordPress-native credentials, not SSO — test with `system.listMethods` first, then `wp.getUsersBlogs`\n\n4. **Enumerate SAML implementation**\n   - Capture a valid SAMLResponse via Burp\n   - Decode the Base64 payload, inspect the XML\n   - Test signature stripping, comment injection, and XML wrapping attacks\n   - Test if SP validates the signature at all (send unsigned assertion)\n\n5. **Test cross-portal session/token reuse**\n   - Log into `partners.shopify.com` type portals\n   - Attempt to use the issued token/cookie against the main admin portal\n   - Look for shared cookie domains, shared JWT secrets, or API tokens that work across contexts\n\n6. **Fuzz auth parameters**\n   - Null/empty passwords, `password[]=array`, SQL in username field\n   - Try `admin`/`admin`, `test`/`test` on staging subdomains\n   - Modify `role`, `is_admin`, `user_type` in JWTs (none algorithm, weak secret)\n\n7. **Check redirect and state parameters**\n   - Does removing `state` from OAuth break anything?\n   - Can you change `redirect_uri` to an open redirect target?\n   - Does the `RelayState` in SAML get validated?\n\n8. **Verify impact by escalating privileges**\n   - Don't stop at login — prove you can access admin functions, other users' data, or sensitive configuration\n   - Screenshot the highest-privilege action you can perform\n\n---\n\n## Legacy-Protocol Matrix (Probe These First on Any Custom-Branded Login)\n\nWhen a target has a custom, branded login UI (e.g. `customlogin.aspx`, `/auth/signin`, `/account/login`), **always probe the platform's legacy protocol endpoints with native credentials** in parallel. These endpoints frequently outlive the custom UI's protections and accept native credentials with NO rate limit, NO MFA challenge, NO CAPTCHA, NO anti-automation. This is the WordPress XMLRPC pattern generalised across CMS / portal / framework stacks.\n\n| Target tech | Legacy endpoint(s) to probe | Native-cred bypass surface |\n|---|---|---|\n| **WordPress** | `/xmlrpc.php` (`system.listMethods`, `wp.getUsersBlogs`, `system.multicall`) | Native WP user/pass; bypasses SSO, MFA, IP-allow rules on `/wp-login.php` |\n| **WordPress (REST)** | `/?rest_route=/wp/v2/users`, `/wp-json/wp/v2/users` | User enumeration anonymously even when login page is hardened |\n| **SharePoint (any version)** | `/_vti_bin/Authentication.asmx` (`Mode` + `Login` SOAP ops) | Native Forms-auth credential; FedAuth cookie returned; no rate limit on this endpoint observed on SP2013 farms — **this is the canonical SP equivalent of the WP XMLRPC bypass** |\n| **SharePoint legacy** | `/_vti_bin/_vti_aut/author.dll`, `/_vti_bin/_vti_adm/admin.dll`, `/_vti_bin/owssvr.dll` | FrontPage RPC; sometimes still wired to credential validators |\n| **SharePoint REST** | `/_api/contextinfo` (POST), `/_api/$metadata` | Anonymous FormDigest issuance; full API surface enumeration |\n| **Atlassian (Jira / Confluence)** | `/rest/auth/1/session` (basic-auth), `/rest/api/2/myself`, legacy `/rest/api/1.0/` | Native credentials accepted on `/rest/auth/1/session` even when Atlassian Crowd / Atlassian Access SSO is enforced on the UI |\n| **Drupal** | `/jsonapi/`, `/user/login?_format=json` | JSON POST endpoint that accepts native passwords; separate from SSO middleware |\n| **Drupal (D7 legacy)** | `/?q=user/login`, `/services/`, `/rest/` | Older REST modules with independent auth |\n| **Joomla** | `/administrator/index.php?option=com_login`, `/api/index.php/v1/users` | Native Joomla credentials accepted on admin entry independent of any front-site SSO |\n| **Exchange / OWA** | `/EWS/Exchange.asmx`, `/Autodiscover/Autodiscover.xml`, `/Microsoft-Server-ActiveSync` | NTLM / Basic; bypasses OWA UI restrictions (MFA, IP-allow). The classic CVE-2020-0688 / CVE-2021-26855 surface |\n| **Citrix NetScaler** | `/vpn/index.html`, `/cgi/login`, `/nf/auth/doAuthentication.do` | Native AD credentials; independent of MFA wrappers |\n| **F5 BIG-IP** | `/mgmt/tm/util/bash`, `/tmui/login.jsp` | Native admin credentials |\n| **Generic ASP.NET app** | `*.asmx?WSDL`, `*.svc?WSDL`, `trace.axd`, `elmah.axd`, `.disco` | Find every web service; many take credentials independently of the WebForms login |\n| **Spring Boot** | `/actuator/*`, `/management/*`, `/api/v1/auth/login`, `/api/v1/swagger-ui` | Actuator endpoints sometimes anonymously enumerable |\n| **Jenkins** | `/jnlpJars/jenkins-cli.jar`, `/script`, `/manage`, `/computer/(master)/script` | API tokens + native auth |\n| **GitLab** | `/api/v3/*` (deprecated but still on old installs), `/api/v4/users`, `/api/v4/projects` | Personal Access Tokens with looser scoping than UI session |\n| **TeamCity** | `/app/rest/users`, `/login.html?username=&password=` (GET-form-login) | Native admin credentials |\n| **Apache Tomcat** | `/manager/html`, `/host-manager/html`, `/manager/text/list` | Native Tomcat realm credentials independent of any front auth |\n| **WebLogic** | `/console/login/LoginForm.jsp`, `/wls-wsat/*` | Native admin |\n| **Oracle EBS / PeopleSoft** | `/OA_HTML/AppsLogin`, `/psp/*/?cmd=login` | Native ERP credentials |\n\n**How to use:**\n1. Identify the tech stack from headers + paths (use `hunt-misc` Attack Surface Signals).\n2. Find the row above that matches.\n3. Probe the legacy endpoint anonymously to confirm it's reachable and not 403/404.\n4. Test with synthetic credentials to confirm it accepts native credential format and returns differential responses (success vs failure).\n5. Verify there is no rate limit, no lockout, no CAPTCHA — burst 10 requests at the same user, confirm uniform timing.\n6. Report as **Critical / High** depending on chain to ATO: an anonymous + unlimited credential brute-force endpoint is consistently Critical on bug-bounty programs.\n\n**Lesson from a authorized engagement:** A an enterprise dealer portal on SharePoint 2013 had a custom branded `customlogin.aspx`. The hunt-auth-bypass skill was loaded but the matrix above did not exist in this document — and the WordPress XMLRPC pattern was not connected to the SharePoint equivalent. `/_vti_bin/Authentication.asmx` was reachable anonymously, accepted unlimited credential attempts with no rate limit and no lockout, and was the highest-impact finding in the engagement. Walking this matrix on the first pass would have surfaced it immediately.\n\n---\n\n## Payload & Detection Patterns\n\n**XMLRPC auth probe (bypasses SSO):**\n```bash\ncurl -s -X POST https://target.com/xmlrpc.php \\\n  -H \"Content-Type: text/xml\" \\\n  -d '<?xml version=\"1.0\"?>\n<methodCall>\n  <methodName>system.listMethods</methodName>\n  <params></params>\n</methodCall>'\n\n# If 200 with method list → XMLRPC is enabled, test auth:\ncurl -s -X POST https://target.com/xmlrpc.php \\\n  -H \"Content-Type: text/xml\" \\\n  -d '<?xml version=\"1.0\"?>\n<methodCall>\n  <methodName>wp.getUsersBlogs</methodName>\n  <params>\n    <param><value><string>admin</string></value></param>\n    <param><value><string>password</string></value></param>\n  </params>\n</methodCall>'\n```\n\n**SAML signature stripping (send unsigned assertion):**\n```python\nimport base64, re\n\n# Decode captured SAMLResponse\nsaml_b64 = \"BASE64_FROM_BURP\"\nsaml_xml = base64.b64decode(saml_b64).decode()\n\n# Strip the Signature element entirely\nstripped = re.sub(r'<ds:Signature.*?</ds:Signature>', '', saml_xml, flags=re.DOTALL)\n\n# Re-encode and submit\nprint(base64.b64encode(stripped.encode()).decode())\n```\n\n**SAML XML comment injection (username confusion):**\n```xml\n<!-- Original NameID -->\n<NameID>attacker@evil.com</NameID>\n\n<!-- Injected to confuse parser -->\n<NameID>attacker@evil.com<!---->.victim@company.com</NameID>\n\n<!-- Or namespace confusion -->\n<NameID xmlns:evil=\"http://evil.com\">victim@company.com</NameID>\n```\n\n**Partner/cross-portal token reuse test:**\n```bash\n# Get token from partner portal\nTOKEN=$(curl -s -X POST https://partners.target.com/login \\\n  -d 'email=attacker@test.com&password=pass' \\\n  -c cookies.txt | grep -o 'token=[^;]*')\n\n# Replay against admin portal\ncurl -s https://admin.target.com/dashboard \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Cookie: $TOKEN\"\n```\n\n**JWT none algorithm attack:**\n```python\nimport base64, json\n\nheader = base64.b64encode(json.dumps({\"alg\":\"none\",\"typ\":\"JWT\"}).encode()).decode().rstrip('=')\npayload = base64.b64encode(json.dumps({\"user_id\":1,\"role\":\"admin\",\"email\":\"victim@company.com\"}).encode()).decode().rstrip('=')\ntoken = f\"{header}.{payload}.\"\nprint(token)\n```\n\n**Grep patterns for auth bypass surface:**\n```bash\n# Find XMLRPC in scope\ngrep -r \"xmlrpc\" scope_urls.txt\n\n# Find SSO indicators in JS\ngrep -rE \"(SAMLResponse|samlRequest|RelayState|onelogin|shibboleth)\" *.js\n\n# Find partner/admin subdomains\nsubfinder -d target.com | grep -E \"(admin|partner|internal|sso|auth|login)\"\n```\n\n---\n\n## Common Root Causes\n\n1. **SSO bypasses local auth entirely at the UI layer, but not at the API layer** — developers disable the login form but forget that API endpoints (`/xmlrpc.php`, REST API, mobile API) have their own auth handlers that still accept native credentials.\n\n2. **SAML signature validation is skipped or optional** — library defaults often don't enforce signature checking; developers use `wantAssertionsSigned: false` or fail to configure the IdP certificate correctly.\n\n3. **Shared session infrastructure across different trust levels** — partner portals and admin portals reuse the same session cookie or JWT secret because they're built on the same internal framework, assuming access control at the application layer is sufficient.\n\n4. **Trust inheritance in multi-tenant architectures** — a token issued in a lower-privilege context (partner, reseller) is accepted in a higher-privilege context because the verification only checks signature validity, not the issuance context.\n\n5. **Plugin/module auth is independent of application auth** — every WordPress plugin that handles auth (contact forms, REST API extensions, WooCommerce) may implement its own auth handler inconsistently with the main site's SSO.\n\n6. **XML parsing inconsistencies** — different XML parsers (used by SP vs. IdP) handle comments, namespaces, and whitespace differently, enabling confusion attacks where the signed content differs from the evaluated content.\n\n---\n\n## Bypass Techniques\n\n| Defense | Bypass |\n|---|---|\n| SSO enforced on login page | Probe alternate entry points: XMLRPC, REST API, mobile API, legacy endpoints |\n| SAML signature validation | XML comment injection, namespace wrapping, signature wrapping (XSW), remove signature entirely |\n| IP allowlisting on admin portal | Use partner portal token if it shares auth backend |\n| Rate limiting on login | XMLRPC allows credential stuffing via `system.multicall` — batches hundreds of auth attempts in one request |\n| CSRF token on login form | SAML flow is POST-based cross-origin by design; no CSRF token needed on `/saml/callback` |\n| JWT signature validation | `alg: none`, key confusion (RS256 → HS256 with public key as secret), brute-force weak secrets |\n| Separate session stores per portal | Check if cookie domain is `.target.com` (wildcard) — cookie bleeds between subdomains |\n| MFA on primary login | If SAML SP doesn't enforce MFA at the assertion level and accepts pre-auth assertions, MFA can be skipped |\n\n**XMLRPC multicall for mass auth bypass:**\n```xml\n<methodCall>\n  <methodName>system.multicall</methodName>\n  <params><param><value><array><data>\n    <value><struct>\n      <member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>\n      <member><name>params</name><value><array><data>\n        <value><string>admin</string></value>\n        <value><string>password1</string></value>\n      </data></array></value></member>\n    </struct></value>\n    <!-- repeat for each credential pair -->\n  </data></array></value></param></params>\n</methodCall>\n```\n\n---\n\n## Gate 0 Validation\n\nBefore writing any report, answer these three questions:\n\n1. **What can the attacker DO right now?**\n   Must be: authenticate as another user OR authenticate without valid credentials OR elevate to admin/privileged role. \"Partial information disclosure\" is not auth bypass.\n\n2. **What does the victim LOSE?**\n   Must identify a concrete asset: account takeover of specific user, access to all admin functions, ability to read/modify other tenants' data, or access to privileged APIs. Abstract \"security control bypass\" without impact is not sufficient.\n\n3. **Can it be reproduced in 10 minutes from scratch?**\n   You must be able to: (a) start from a fresh browser/session, (b) follow your exact steps, and (c) arrive at authenticated access to a protected resource. If reproduction requires special preconditions you can't re-create (a specific victim's active session, timing windows), the report needs more work.\n\n---\n\n## Real Impact Examples\n\n**Scenario 1 — SSO Enforcement Bypassed via Forgotten Protocol Endpoint**\nA large ride-sharing company enforced SSO (via OneLogin) on all WordPress-based internal/public properties. The XMLRPC endpoint (`/xmlrpc.php`) remained active and accepted WordPress-native credentials entirely independent of the SSO flow. An attacker with any valid WP-native credentials (obtained via credential stuffing or from a previous breach) could authenticate directly through XMLRPC, bypassing MFA, SSO policies, and IP restrictions enforced on the main login form. Impact: Full authenticated access to all WordPress functions available to that user role, including content management and potentially admin functions.\n\n**Scenario 2 — SAML Assertion Forgery via Signature Validation Failure**\nA major enterprise communication platform's SAML SP implementation failed to properly validate assertion signatures in specific edge cases. By manipulating the XML structure of a captured SAMLResponse (specifically through comment injection or namespace prefix attacks), an attacker could modify the `NameID` value to impersonate any user in an organization — including workspace administrators — without possessing that user's credentials or private key material. Impact: Complete account takeover of any user within a SAML-enabled organization; attacker gains access to all messages, files, and integrations in the workspace.\n\n**Scenario 3 — Cross-Portal Privilege Escalation via Shared Auth Backend**\nAn e-commerce platform's partner/reseller portal issued authentication tokens that were validated by the same backend service as the merchant admin portal. A partner-level account (lower trust, external-facing) could use its issued credentials or tokens to authenticate directly against admin-tier API endpoints, bypassing the merchant onboarding and permission assignment flow. Impact: A malicious partner could access any merchant's admin panel, modify store configurations, exfiltrate customer PII and payment data, or install malicious scripts — affecting thousands of merchant storefronts.\n\n---\n\n## Disclosed Report Citations (Backfill +8 — 2016-2025)\n\nThe following real, verified bug-bounty / coordinated-disclosure cases extend this skill. Spans 4 SAML subclasses, 4 JWT subclasses, 1 legacy-protocol (XMLRPC), and 2 partner-portal cross-domain reuse patterns.\n\n5. **GitHub Enterprise Server — SAML XSW via parser differential (CVE-2025-25291/25292)** ([H1 #2579939](https://hackerone.com/reports/2579939) · [Blog](https://github.blog/security/sign-in-as-anyone-bypassing-saml-sso-authentication-with-parser-differentials/))\n    - Subclass: SAML signature stripping / XSW (parser-differential variant)\n    - Payload: signed SAML response; inject a sibling `<Assertion>` so REXML (signature-checker) and Nokogiri (business-logic reader) resolve different nodes via the same XPath. Signature validates against benign node; SP consumes attacker-controlled `<NameID>admin@target</NameID>`\n    - Root cause: two XML parsers used for verification vs consumption return different elements for the same XPath\n    - Year: 2025 — GitHub Security Lab bounty (program max class, internally rated Critical)\n\n6. **GitHub Enterprise — SAML signature bypass on encrypted assertions (CVE-2024-4985)** ([H1 #2475347](https://hackerone.com/reports/2475347) · [ProjectDiscovery advisory](https://projectdiscovery.io/blog/github-enterprise-saml-authentication-bypass))\n    - Subclass: SAML signature stripping (XSW family) when encrypted-assertions feature enabled\n    - Payload: forge SAML response with attacker-controlled assertion; exploit improper signature verification on the encrypted-assertion code branch; provision arbitrary user including `site_admin`\n    - Root cause: improper cryptographic signature verification on the encrypted-assertion code branch\n    - Year: 2024 — bounty undisclosed, CVSS 10.0\n\n7. **Uber — SAML auth bypass on `uchat.uberinternal.com`** ([H1 #223014](https://hackerone.com/reports/223014))\n    - Subclass: SAML signature stripping / improper assertion verification (OneLogin SP-side)\n    - Payload: replay/modify SAML assertion with forged `NameID`; SP did not strictly validate signature scope, so attacker-controlled assertion accepted, granting OneLogin SSO session to internal chat\n    - Root cause: improper SAML signature verification on SP implementation\n    - Year: 2017 — **$8,500**\n\n8. **Uber — OneLogin SSO bypass via WordPress XMLRPC** ([H1 #138869](https://hackerone.com/reports/138869))\n    - Subclass: WordPress XMLRPC bypassing SSO (legacy-auth path not gated) — canonical Legacy-Protocol Matrix case\n    - Payload: OneLogin plugin auto-created WP users with literal password `@@@nopass@@@`. SSO plugin blocked `wp-login.php` only. POST `xmlrpc.php` with `wp.getUsersBlogs` + known shared password → authenticated as any previously-SSO'd user\n    - Root cause: SSO enforcement applied at one auth surface (wp-login) but legacy XML-RPC path retained password auth with a guessable shared password\n    - Year: 2016 — **$7,000**\n\n9. **Slack — SAML \"confused-deputy\" assertion reuse** ([Writeup](http://blog.intothesymmetry.com/2017/10/slack-saml-authentication-bypass.html))\n    - Subclass: partner-portal / cross-IdP assertion reuse (audience-restriction not validated)\n    - Payload: take an old expired GitHub-signed SAML assertion (different audience, different subject) → present to Slack ACS → Slack logs attacker in as the asserted username\n    - Root cause: no audience-restriction nor freshness check; trust extended across IdPs\n    - Year: 2017 — **$3,000**\n\n10. **HackerOne — SAML signup domain enforcement bypass via control characters** ([H1 #2101076](https://hackerone.com/reports/2101076))\n    - Subclass: partner-portal / SAML domain-binding bypass via unicode control characters\n    - Payload: new user sign-up at SAML-enforced org; append trailing control character (e.g., `\\r`, ``) to email → domain comparison normalises away, signup proceeds → unauthorised access to the org\n    - Root cause: inconsistent unicode/control-char normalisation between domain check and identity write\n    - Year: 2024 — bounty awarded (amount undisclosed)\n\n11. **8x8 / Jitsi-Meet — JWT alg-confusion (asymmetric verifier accepts symmetric alg)** ([H1 #1210502](https://hackerone.com/reports/1210502))\n    - Subclass: JWT alg-confusion (RS256 → HS256 using public key as HMAC secret)\n    - Payload: server publishes RS256 verification public key. Send a token with header `{\"alg\":\"HS256\"}` signed with that public key as the HMAC secret → Prosody module validates and admits attacker into authenticated/moderator room\n    - Root cause: verifier did not enforce `alg=RS256`; allowed symmetric algorithm using the public key as shared secret\n    - Year: 2021 — bounty undisclosed\n\n12. **Argo CD (Internet Bug Bounty) — JWT audience claim not validated (CVE-2023-22482)** ([H1 #1889161](https://hackerone.com/reports/1889161))\n    - Subclass: token-scope / audience check at issuance not at use (cross-audience token confusion)\n    - Payload: obtain any RS256-signed token signed by the cluster's OIDC issuer but minted for a different `aud` (e.g., `kubernetes`) → present it as bearer to Argo CD API → API treats it as valid because it accepted the issuer's signature and skipped `aud` enforcement\n    - Root cause: `aud` claim not enforced; signature-trust extended across audiences\n    - Year: 2023 — **$2,400** via IBB\n\n---\n\n## Duende BFF — Token-Confusion & Session-Fixation (2024-2026 surface)\n\nDuende BFF deployments expose two distinct auth-bypass families beyond the CSRF angle covered in `hunt-csrf`. Both are documented architectural realities, not unicorn CVEs.\n\n### Attack class 1 — YARP `UserOrClient` / `UserOrNone` privilege escalation\n\n`Duende.BFF.Yarp` attaches access tokens to proxied routes via `WithAccessToken(TokenType.X)` metadata. The **misconfig pattern**: developer marks a route `UserOrClient` (use user token if logged in, else fall back to *client-credentials* token) intending it for a \"public catalog\" endpoint. The client-credentials (M2M) token frequently has broader scope (`api.admin`, `internal.read`) than any user token. An **unauthenticated** attacker hitting that route gets the request proxied with the **service-account token attached** to the downstream API — privilege escalation by design when the downstream trusts the bearer.\n\n**Payload shape:** identify a BFF route marked `TokenType.UserOrClient` (visible via 401-vs-200 differential when no session, or via leaked OpenAPI/NSwag spec). Hit it with no cookies → BFF forwards with M2M token granting admin-scope downstream. ([docs.duendesoftware.com/bff/fundamentals/apis/yarp](https://docs.duendesoftware.com/bff/fundamentals/apis/yarp/))\n\n**Adjacent confirmed CVE:** **CVE-2024-51987** in `Duende.AccessTokenManagement.OpenIdConnect` — *\"HTTP client uses incorrect token after refresh\"* — materially the same family of token-confusion at the proxy layer. Moderate severity, fixed 2024. ([GHSA-...51987](https://github.com/advisories?query=duende))\n\n### Attack class 2 — Cookie-domain wildcard + sliding expiration = persistent ATO\n\nWhen BFF session cookie has `Domain=.example.com` (devs do this to share login across `app.` and `admin.`), the `__Host-` prefix protection is dropped. Any sibling subdomain — including a **taken-over** one (`legacy.example.com` CNAMEd to deprovisioned Heroku/S3) — can write `Set-Cookie: .AspNetCore.Cookies=<attacker_session>; Domain=.example.com`. Victim hits `app.example.com` carrying the attacker's session = **session-fixation ATO**.\n\nIf `SlidingExpiration=true` (default) and `ExpireTimeSpan` is large (e.g. 8h), an exfiltrated cookie remains valid and keeps sliding forward as long as the attacker periodically calls `/bff/user`. There is no server-side refresh-token rotation check on the cookie itself — only the OIDC token (server-side) rotates. Persistent ATO window per stolen cookie.\n\n**Payload shape:** subdomain takeover → write the BFF session cookie with `Domain=.example.com` → victim's next visit to `app.example.com` adopts attacker's session. Cron-curl `GET /bff/user -H 'X-CSRF: 1' -b '.AspNetCore.Cookies=...'` every 6h indefinitely to keep the session alive.\n\n**Hardening reference:** [docs.duendesoftware.com/bff/fundamentals/session/handlers](https://docs.duendesoftware.com/bff/fundamentals/session/handlers/), [nestenius.se BFF cookie guide](https://nestenius.se/net/bff-in-asp-net-core-3-the-bff-pattern-explained/), [Langkemper on `__Host-` prefix](https://www.sjoerdlangkemper.nl/2017/02/09/cookie-prefixes/).\n\n### Attack class 3 — `/bff/user` claim disclosure\n\n`GET /bff/user` returns the **full claim set** of the active session as a JSON array — `sub`, `sid`, `email`, `bff:session_expires_in`, `bff:session_state`, `bff:logout_url`, plus every custom claim the OP issued (department, role, internal employee ID, tenant ID). The endpoint is gated only by session cookie + `X-CSRF: 1`. If `AnonymousSessionResponse=Response200` is set, the endpoint also acts as a session probe (200 + claims vs 200 + `null`) usable as an auth-state oracle. Low/Medium info-disclosure on its own; valuable as recon for the YARP token-confusion class above. ([docs.duendesoftware.com/bff/fundamentals/session/management/user](https://docs.duendesoftware.com/bff/fundamentals/session/management/user/))\n\n### Evidence strength + reporting tip\n\nNo Duende.BFF-direct CVE exists. The three classes are exploitable via real-world misconfigurations; CVE-2024-51987 and CVE-2025-26620 in the adjacent `Duende.AccessTokenManagement` packages make token-confusion a confirmed family. **Report by chain impact** (e.g., \"low-priv session reaches admin-scope downstream API via UserOrClient route\" → Critical) rather than by CVE citation, since the issue is design-level.\n\nCross-references for the chain:\n- `hunt-csrf` — the role-partitioned antiforgery class (the CSRF angle on the same BFF surface).\n- `hunt-subdomain-takeover` / `hunt-subdomain` — required primitive for the cookie-domain attack.\n\n---\n\n## Function-Level Access Control (Broken Authorization)\n\nAuthentication bypass gets you *in*; **function-level access control** failures let an already-authenticated low-privilege user reach privileged *functions* the UI never offered them. This is the authorization sibling of `hunt-idor` (object-level access) — test both whenever you hold any authenticated session.\n\n**The sibling-function rule:** if 9 endpoints under a path enforce auth/role middleware, the 10th that doesn't is your bug. Admin route families are the highest-yield place to look:\n\n```\n/api/admin/users   → has auth middleware\n/api/admin/export  → often MISSING it\n/api/admin/delete  → often MISSING it\n/api/admin/reset   → often MISSING it\n```\n\n**Anti-patterns to grep for:**\n```javascript\n// Missing middleware on a sibling route\nrouter.get('/admin/users',  authenticate, authorize('admin'), getUsers);\nrouter.get('/admin/export', getExport);            // No middleware!\n\n// Client-side role check only — server never re-checks\nif (user.role === 'admin') showAdminButton();      // frontend gate\napp.post('/api/admin/delete', deleteUser);         // no server-side check\n```\n\n**How to hunt:** enumerate every privileged endpoint (admin/export/delete/reset/impersonate, GraphQL admin queries), then replay each from a *regular* authenticated session — and again with no session. A 200 (or a differential vs the 403 its siblings return) is broken function-level access control.\n\n**Real paid example — HackerOne TrustHub:** `POST /graphql` with the `TrustHubQuery` operation had no authorization check — a regular user could read all vendors' data (CVSS 8.7, High). The object-level variant (e.g. a WebSocket `get_history` accepting an arbitrary UUID with no ownership check) belongs to `hunt-idor`.\n\n---\n\n## Related Skills & Chains\n\n- **`hunt-idor`** — Auth bypass without object-level access is half a finding; pair them. Chain primitive: legacy `/v1/users/{id}` route missing both auth middleware AND ownership check = unauthenticated cross-tenant data read via direct ID substitution → full PII dump from \"I am nobody\" starting position.\n- **`hunt-ato`** — Auth-bypass primitives feed the ATO funnel. Chain primitive: XMLRPC native-cred acceptance + no rate limit on `wp.getUsersBlogs` → credential-stuff with breach corpus from `hunt-misc` recon → `system.multicall` batches 1000 cred pairs per request → one valid pair = ATO bypassing the SSO + MFA the UI enforces.\n- **`hunt-sharepoint`** — The SP equivalent of the WordPress XMLRPC pattern lives here. Chain primitive: `/_vti_bin/Authentication.asmx` anonymous reachable + native Forms-auth credential accepted + zero rate limit = unlimited credential brute-force endpoint bypassing custom-branded `customlogin.aspx` protections → FedAuth cookie → full SharePoint farm access.\n- **`security-arsenal`** — Pull the JWT-attack payloads section (alg=none, kid path-traversal, JWK injection, RS256→HS256 key confusion) when JWT validation is the auth wall; pull the SAML signature-stripping section when the SP accepts unsigned assertions.\n- **`triage-validation`** — Run the Pre-Severity Gate before claiming Critical on an \"auth bypass\" that only enumerates usernames or only reveals a 401-vs-403 differential. Username enumeration alone without lockout-amplification is consistently N/A or Informational on H1.","author":"@elementalsouls","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/elementalsouls/Claude-BugHunter/tree/main/skills/hunt-auth-bypass","license":"MIT","category":"coding","lang":"en","tokens":7469,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":["admin.target.com","blog.intothesymmetry.com","docs.duendesoftware.com","evil.com","github.blog","hackerone.com","idp.company.com","nestenius.se","partners.target.com","projectdiscovery.io","target.com","www.sjoerdlangkemper.nl"]}}