Automated SAML, OAuth 2.0/OIDC & JWT attack testing with verdicts.
The first Burp extension that automates the verdict, not just the tampering, across SAML 2.0, OAuth 2.0 / OIDC, and JWT/JOSE in one tool.
The established SSO/JWT extensions are manual editors — they help you craft a tampered message, but you send it and you decide by eye whether it was accepted:
| Existing BApp | What it does | What it leaves to you |
|---|---|---|
| SAML Raider | Manual SAML editor, XSW helpers, certificate management | Send each variant, read each response, judge pass/fail by hand |
| EsPReSSO | SSO detection/highlight; SAML / JSON / JWT editors; WS-Attacker hooks | Same — manual edit-and-eyeball |
| JWT Editor | Manual JWT edit / sign / alg=none |
Same — you replay and interpret |
This extension runs the full battery automatically and issues an automated verdict. For every
test case it sends the variant(s), then decides Vulnerable / Secure / Inconclusive by
response-diff against the untampered baseline, gated by a negative control (a deliberately
invalid message) so that an endpoint which accepts anything can't produce a false positive.
Blind classes — XXE, XSLT, and jku/x5u/redirect_uri SSRF — are confirmed out-of-band with
Burp Collaborator. No existing BApp automates the verdict — that is the novelty. Every finding
carries the exact request/response pair that proves it, so results are always reproducible.
It covers all three protocols in one pass — SAML, OAuth/OIDC, and JWT as an independent module
(JWTs are tested wherever they appear: OAuth id_tokens, SAML bearer contexts, session cookies, or
plain Authorization: Bearer API calls) — and still lets you push any variant to Repeater for
manual confirmation.
⚠️ Authorized testing only. Use this against systems you own or are explicitly permitted to test. The tool sends live, tampered authentication requests.
- Select one or many requests in Proxy → HTTP history (Ctrl/Shift-click for many).
- Right-click → “Send to SAML Tester” or “Send to OAuth 2.0 Tester”. This loads the request(s) into the Tester tab and fills a test-case dropdown — nothing is sent yet.
- Choose how to run:
- pick a single case and Run selected to test it one at a time, or
- Run ALL to fire the whole battery. For each case the extension decodes the message (SAML: Base64 for POST binding, raw-DEFLATE+Base64 for Redirect binding), applies the attack, re-encodes, replays, and judges the response by response-diff — did the server accept the forgery (Vulnerable) or reject/redirect-to-error it (Secure)?
- Results stream into the Tester tab. Select any row to view Original vs Attack and the Changes (highlighted) diff, tick “Show only Vulnerable” to focus, filter by Category, and “Send selected to Repeater” to confirm manually.
Each finding carries the literal request that produced it, so verdicts are always verifiable — the heuristics get you to the candidates fast, your eyes confirm the kill.
Signature attacks
- Signature stripping — remove all
<Signature>blocks (SP requires no signature) - Empty SignatureValue — blank the signature bytes (content not verified)
- Certificate faking — replace the embedded
X509Certificate(SP trusts the in-message cert → attacker re-signs) - Signature algorithm downgrade — force weak
rsa-sha1
XML Signature Wrapping (XSW1–XSW8) — the 8 classic variants (Somorovsky et al. / SAML Raider). Each places a forged, admin-identity assertion in a different position relative to the original signed element:
- XSW1/XSW2 target the Response signature (wrap / detached)
- XSW3/XSW4 insert the evil assertion before / wrapping the signed assertion
- XSW5/XSW6 borrow / hide the signature inside the evil assertion
- XSW7 hides the evil assertion in
<Extensions>; XSW8 hides the original in a Signature<Object>
Assertion & condition tampering (all without re-signing)
- NameID forge — escalate identity to an admin account
- Attribute/role escalation — set a role attribute to
Administrator - Issuer spoofing — point
Issuerat an untrusted IdP - Audience restriction bypass — change
Audience - Token recipient confusion — change
Recipient/Destination - Expiry tampering — push
NotOnOrAfterto 2099 - InResponseTo removal — SAML login CSRF / unsolicited response
- XML comment injection in NameID — canonicalization truncation
Parser / processing attacks
- XXE injection —
DOCTYPE/entity in the assertion - XSLT injection — malicious
<Transform>stylesheet - Assertion replay — submit the same assertion twice (single-use enforcement)
Static checks (missing protections, no request sent):
- Missing
state(login CSRF / code injection) - Missing / weak PKCE
code_challenge(andplainmethod) - Missing
nonceon OIDC (scope=openid) - Implicit flow in use (
response_type=token/id_token) - Insecure
redirect_uri(http://) - Missing client authentication on the token endpoint (no
client_secret/Authorization)
Active checks (mutate + replay + judge):
redirect_urihijack — swap host to an attacker domainredirect_urisuffix/subdomain bypass — defeat naive prefix matchingredirect_uripath /@-userinfo bypassredirect_uriloopback/userinfo bypassredirect_uriparameter pollution — duplicate param, server reads the wrong copy- Implicit downgrade (
response_type=token) - Hybrid flow downgrade (
response_type=code id_token token) client_idconfusion — swap to an unknown client- Silent auth abuse (
prompt=none) - Scope escalation — request
admin/offline_access - Authorization-code replay — send a
codetwice; single-use must fail the 2nd
OIDC id_token / JWT attacks (on id_token, id_token_hint, assertion)
alg=none— strip algorithm + signature- Signature stripping — keep header/payload, blank signature
- Claim escalation — forge
sub/email/rolewithout re-signing
- Burp Suite Community or Professional. All active test cases (send, response-diff verdict,
Send to Repeater) work in both. Burp Collaborator OOB confirmation for XXE / XSLT /
jku/x5u/redirect_uriSSRF requires Professional; without it those checks fall back to in-band heuristics and are reported conservatively. - Nothing is sent until you act. The Proxy handler only highlights auth traffic; the tool issues requests only when you choose Run selected / Run ALL or Send to Repeater.
- Build requires JDK 21 and Gradle.
Source-only repo, built with Gradle (JDK 21). The Montoya API is compileOnly and fetched from
Maven Central — nothing is bundled and no jars are committed.
gradle clean jarThis produces build/libs/auth-auditor-1.1.0.jar.
Extensions → Installed → Add → Extension type Java → select
build/libs/auth-auditor-1.1.0.jar. A new “Auth Auditor” suite tab appears, and the
right-click items (Send to SAML / OAuth 2.0 / JWT Tester, Send SAML to Decoder) are added to
Proxy/Repeater/etc.
The verdict is reached the way an analyst reasons by hand: tamper the request, then compare the
response to the legitimate baseline. For an integrity test (strip signature, forge NameID,
alg=none, …) a properly-secured server must reject the manipulated message, so:
- tampered request rejected (4xx, error markers) → Secure — even if the error page echoes our payload back;
- the redirect / response changes to a login/error page → Secure (the server treated the forgery differently);
- the response is unchanged vs the valid baseline (same status, same
Location, ~same body) → the server accepted the forgery. This is reported Vulnerable only if a negative control — a deliberately-invalid message sent first — was rejected, proving the endpoint actually validates. If even the bad control was accepted, the endpoint is ignoring the token, so the result is Inconclusive instead (no false "Vulnerable"); - changed but not a clear rejection → Inconclusive.
For OAuth redirect tests, the proof of an open redirect is the Location header actually
pointing at the attacker host — reflection in an error body never counts. Each finding shows the
Original and Attack request/response side by side and is gated by the same negative control.
The older absolute classifier is still used as a fallback when no baseline is available:
- Rejection dominates. Any HTTP 4xx/5xx, or a rejection marker in the body
(
invalid signature,access denied,invalid_grant,redirect_uri_mismatch, …) is reported Secure — even if the error page echoes our injected value back. (This removes the classic false positive where a400 Bad Requestwhose body repeats the badredirect_uriwas flagged Vulnerable.) - Open-redirect proof is the
Locationheader, not the body. A redirect test is only Vulnerable when the response'sLocationheader actually points at the attacker host (authority or@-userinfo) — reflection inside an error body does not count. - Baseline-aware. Each target's original, untampered response is captured first. If a tampered request produces an outcome indistinguishable from that baseline (same status, same redirect, no new session cookie), the verdict is Inconclusive, not Vulnerable — because tampering changed nothing observable. The Original and Attack request/response are shown side by side so you can make the final call.
- Vulnerable (accepted): a distinct success marker (
logout,dashboard,access_token), a freshly granted sessionSet-Cookie, or a redirect to a non-login app resource that the baseline did not already produce.
Always confirm a Vulnerable finding in Repeater. Some checks have inherent caveats — e.g. SAML assertions are often single-use, so replayed baselines can fail for benign reasons; scope-escalation acceptance must be confirmed by inspecting the issued token’s scopes.
- Proxy auto-highlight. SAML and OAuth/OIDC requests are painted blue in Proxy history as they pass through (passive — never modifies traffic), with a note saying which protocol, so the requests worth testing jump out.
- Original vs Attack panes. Every finding shows the Original request/response and the Attack request/response side by side.
- Separate SAML / OAuth. Filter findings by Category (All / SAML / OAuth2.0), and force a battery with “Send to SAML Tester” / “Send to OAuth Tester” in addition to auto-detect.
- SAML Decoder workbench (SAML-Raider style). A “SAML Decoder” sub-tab and a
“Send SAML to Decoder” context item: decode a
SAMLRequest/SAMLResponse(POST or Redirect binding) to readable, pretty-printed XML, edit it by hand, then re-encode it for the original binding to paste into Repeater. - Inline decoder tab everywhere SAML appears. A “SAML (decoded)” tab is added to Burp's request editor (Proxy / Repeater / Intruder) for any request carrying a SAML message — view and edit the decoded XML in place; edits are re-encoded on send. A test-case dropdown applies any mutation and “Send mutated → Repeater” / “Send ALL cases → Repeater” queue the whole battery for manual testing.
- Inline OAuth tab. An “OAuth (test cases)” tab decodes any JWT (
id_token,id_token_hint,assertion,access_token) to readable JSON and offers the OAuth tampering battery → Repeater the same way. - Negative control. Before judging, the tool sends a deliberately-invalid message; if the endpoint accepts even that, "accepted" results are downgraded to Inconclusive to avoid false positives.
- "Changes (highlighted)" view. Selecting a finding shows the original values on the left and the attack values on the right, with every changed line highlighted — decoded SAML XML for SAML findings, request parameters otherwise — so you can eyeball exactly what was mutated and compare it by hand before confirming.
- Burp Collaborator OOB confirmation. When Collaborator is available, blind issues are confirmed out-of-band: SAML XXE and XSLT point an external fetch at a Collaborator URL, and OAuth redirect_uri / request_uri SSRF do the same. A real interaction turns the verdict into a definitive Vulnerable [OOB confirmed]; if Collaborator is unavailable the tool falls back to in-band heuristics.
- Separate SAML / OAuth context menu. The combined "Send to SAML/OAuth Tester" item was removed — right-click offers "Send to SAML Tester" and "Send to OAuth 2.0 Tester" directly.
- Full
redirect_uribypass matrix (TC-3). Host-correct attacker-host variants (hijack, subdomain suffix, userinfo@, backslash, prefix-path, loopback) confirmed by the Location host oracle, plus scheme-downgrade / path-traversal / omission and parameter-pollution — shared by the automated tester and the inline editor. - Mix-up defense check (RFC 9207). Flags whether the authorization response carries
iss. - Run one-by-one or Run ALL. Right-click → "Send to SAML Tester" / "Send to OAuth 2.0 Tester" / "Send to JWT Tester" now loads the request(s) into the Tester tab and populates a test-case dropdown. Pick a single case and Run selected, or Run ALL to fire the whole battery. (The negative-control gate is still computed automatically so single-case verdicts stay accurate.)
- JWT is a first-class target. JWTs are detected wherever they live —
Authorization: Bearer, a parameter (id_token/access_token/assertion/…), or a cookie — highlighted cyan in Proxy, and get their own "Send to JWT Tester", JWT category filter, and "JWT (decoded)" inline editor tab. Battery:alg=none, signature stripping, claim/scope/aud/isstampering,exp/nbfbypass,kidpath-traversal / SQLi, HS256 weak-secret / alg-confusion probe, andjku/x5uSSRF confirmed out-of-band with Collaborator — each judged by response-diff against the baseline and gated by a corrupted-signature negative control.
See TEST-COVERAGE.md for the full mapping of all 25 SAML + 30 OAuth reference test cases to how each is handled (automated / manual-via-editor / observational / out-of-scope).
src/main/java/com/pentest/samloauth/
SamlOAuthExtension.java entry point + context menu
core/ Detector, TestEngine, ResponseEvaluator, Params, TestResult
saml/ SamlCodec, SamlTarget, SamlMutations, SamlTester
oauth/ OAuthTester
ui/ MainTab, FindingsTableModel
model/ Finding, TargetType, TestStatus, Severity
src/main/resources/META-INF/services/burp.api.montoya.BurpExtension
test/SelfTest.java standalone core tests (no Burp needed)
build.gradle gradle clean jar -> build/libs/auth-auditor-<version>.jar
MIT — see LICENSE.