JWT Attacks
A complete guide to understanding, detecting, exploiting, and preventing JWT Attacks vulnerabilities.
Introduction
JWT Attacks
The Complete ANAS EDUCATION Course (Beginner Edition)
1. Introduction
Imagine you open your PC and visit `anastech.com`.
You go to the login page. The browser opens:
You type your email and password. You click "Submit".
If the login is correct, the server replies with an interesting cookie:
That long string in the `Set-Cookie` header is a JWT (JSON Web Token). Three blocks of letters and numbers, separated by two dots.
From this point on, every time your browser makes a request to anastech.com, it sends that cookie back:
The server looks at the JWT, reads who you are (`anas`), and decides what you can see.
Now here is the strange part: the server does not remember anything about your login. It does not store a session in a database. It does not write your username on a sticky note. Everything the server needs to know about you is inside that JWT itself.
This is great for speed. The server can scale to millions of users without a session database. But it is also dangerous, because if you can change what is inside the JWT, you can pretend to be anyone:
- ●Change `"role":"user"` to `"role":"admin"` ==> you are admin.
- ●Change `"user":"anas"` to `"user":"carlos"` ==> you are Carlos.
- ●Add new claims, remove claims ==> the server reads whatever you put.
The only thing stopping you is the signature, the third block at the end of the JWT. The signature is a cryptographic proof that the JWT was issued by the server and has not been changed.
A JWT attack is anything that lets you defeat the signature check. Once you can defeat it, you own the application.
This course teaches you the JWT bug class from zero. By the end you will know:
- ●What a JWT really is, byte by byte.
- ●How servers check signatures.
- ●Seven different ways attackers break the signature check.
- ●How to find each bug.
- ●How to fix each bug.
You do not need to be an expert. You just need to read carefully.
2. How It Works
To find these bugs, you first need to understand JWTs in detail.
Step 1. The three parts of a JWT
A JWT is a string with three parts separated by dots:
Each part is base64url-encoded (a relative of base64 that works in URLs).
Example token:
Split at the dots:
Step 2. What is inside the header
Base64-decode the first part. You get JSON:
- ●`alg` ==> the algorithm used to sign the token. Common values: `HS256`, `RS256`, `none`.
- ●`typ` ==> the type of token. Almost always `JWT`.
There can also be optional fields:
- ●`kid` ==> Key ID. Tells the server which key to use to verify.
- ●`jwk` ==> JSON Web Key. The actual public key embedded in the token.
- ●`jku` ==> JWK Set URL. A URL where the server can fetch keys.
These optional fields are where many bugs live. We will come back to them.
Step 3. What is inside the payload
Base64-decode the second part. You get JSON:
- ●`user` ==> the username (custom claim).
- ●`role` ==> the role (custom claim).
- ●`iat` ==> issued-at timestamp.
- ●`exp` ==> expiration timestamp.
The standardized JWT claims include `iss` (issuer), `sub` (subject), `aud` (audience), `exp` (expiration), `nbf` (not-before), `iat` (issued-at), `jti` (token ID).
Important: the payload is just base64. Anyone can read it. Anyone can decode it at `jwt.io`. The payload is not encrypted, only encoded. The privacy comes from the signature, not from the encoding.
Step 4. What is the signature
The signature is calculated by the server like this:
For HS256 (HMAC with SHA-256), this is:
For RS256 (RSA with SHA-256):
The server keeps `secret_key` (HS256) or `private_key` (RS256) secret. Without the secret, no one can produce a valid signature.
Step 5. How the server verifies a JWT
When the server receives a JWT in a cookie or header, it:
- ●Splits the JWT into header, payload, signature.
- ●Base64-decodes the header to read the `alg`.
- ●Recomputes the signature using its secret key.
- ●Compares the recomputed signature to the one in the JWT.
If they match, the server trusts the payload.
If the server skips or weakens any step in this chain, an attack appears.
Step 6. JWT vs JWS vs JWE
These three terms confuse many beginners. Here is the truth:
- ●JWT is just a format. JSON wrapped in three base64-encoded parts.
- ●JWS (JSON Web Signature) adds a signature. The payload is readable but cannot be modified without breaking the signature. This is what most "JWTs" actually are.
- ●JWE (JSON Web Encryption) adds encryption. The payload is encrypted, not just signed.
When someone says "JWT", they almost always mean a JWS. JWEs are rarer in the wild. This course focuses on JWS attacks.
3. Attack Flow
JWT attacks all follow the same general pattern. Read each step in order.
Step 1. Get a valid JWT
Log in to the target normally. Capture the JWT from the response (it lives in cookies, the `Authorization: Bearer ...` header, or sometimes in the URL).
Step 2. Decode the JWT
Paste the JWT into one of:
- ●https://jwt.io (web UI)
- ●Burp Suite's JWT Editor extension
- ●Command line: `echo "HEADER_PART" | base64 -d`
Look at the header and payload. Note:
- ●The algorithm (`alg`).
- ●The user identifier claim (`sub`, `user`, `username`, `email`).
- ●The privilege claim (`role`, `isAdmin`, `permissions`).
- ●The expiration (`exp`).
- ●Optional header parameters (`kid`, `jwk`, `jku`, `x5u`).
Step 3. Identify the attack class
Step 4. Build the malicious JWT
Change the payload to give yourself privilege:
Re-sign or omit the signature according to the attack class.
Step 5. Send the malicious JWT
In Burp Repeater, replace the original cookie or `Authorization` header with your forged token. Send.
- ●Response is 200 with admin content ==> attack works.
- ●Response is 401/403 ==> signature check held. Try another attack class.
Step 6. Document
Every JWT engagement walks this exact flow.
4. Why Developers Make This Mistake
The developer who wrote this:
was thinking:
- ●"I have the JWT. I read the role. The role says admin. Done."
- ●"The JWT is signed. No one can change it."
Each thought has a hidden flaw:
- ●`jwt.decode()` does NOT verify the signature. It only base64-decodes the payload. The correct method is `jwt.verify()`. Many devs confuse the two.
- ●A signed JWT is only as secure as the verification. If you do not check the signature, the JWT is just a base64-encoded JSON object the user can freely edit.
The same kind of confusion shows up in many forms:
- ●Skipping signature verification entirely (just calling `decode()`).
- ●Trusting `alg: none` because the library accepts it by default.
- ●Using a weak or default secret like `"secret"`, `"key"`, `"changeme"`, or the company name.
- ●Trusting `kid`, `jwk`, or `jku` headers without strict validation.
- ●Not enforcing which algorithm is expected, so an attacker can switch RS256 to HS256.
The root cause is the same as in many web bugs: user-controlled input flowing into a security decision without validation. In the JWT case, the user controls:
- ●The header (including `alg`, `kid`, `jwk`, `jku`).
- ●The payload.
- ●The signature.
The developer must NOT trust any of these without strict server-side checks.
5. Beginner Summary
- ●A JWT is three base64 parts separated by dots: header, payload, signature. Anyone can read the header and payload. The signature is the only protection.
- ●A JWT attack is anything that lets you change the payload (or the header) and still get the server to accept the token.
- ●The most common attacks are: skipping verification, setting `alg: none`, brute-forcing weak HS256 secrets, injecting your own key via `jwk` or `jku` headers, traversing the filesystem via `kid`, and confusing the algorithm (RS256 to HS256).
- ●The impact is almost always severe: privilege escalation to admin, impersonation of other users, full account takeover.
- ●The fix: use a battle-tested library, always call `verify` (not just `decode`), enforce a fixed expected algorithm, never trust user-controlled key references, and keep your secret long and random.
If you remember those five lines, you have the whole concept.
6. Visual Explanation
The structure of a JWT
The vulnerable verification chain
Attack #1: skipped signature
Attack #2: alg = none
Attack #7: HS256/RS256 confusion
Burn these into memory.
7. Definition
Technical definition. JWT attacks are a class of authentication and authorization vulnerabilities in which a JSON Web Token's signature verification can be bypassed, weakened, or confused, allowing an attacker to forge or tamper with tokens accepted by the server. Common subclasses include unverified signatures, algorithm-none acceptance, weak HMAC secrets, header parameter injection (`jwk`, `jku`, `kid`), and algorithm confusion attacks (HS256 vs RS256). Outcomes typically include privilege escalation, account impersonation, and full authentication bypass. Tracked under CWE-345 (Insufficient Verification of Data Authenticity), CWE-347 (Improper Verification of Cryptographic Signature), and CWE-327 (Use of a Broken or Risky Cryptographic Algorithm).
Beginner-friendly definition. JWT attacks are tricks that let you change the user info inside a token (like making yourself admin) and still get the server to believe you.
Why it matters. JWTs sit at the center of authentication for modern web and mobile applications. A successful JWT attack typically results in immediate privilege escalation or full account takeover. They are common in SaaS platforms, microservice architectures, mobile-app backends, and single-page applications. PortSwigger documents seven distinct JWT-attack labs ranging from Apprentice (unverified signature, alg=none) through Practitioner (weak secret, jwk, jku, kid path traversal) up to Expert (algorithm confusion, including the no-exposed-key variant).
Common affected systems.
- ●SaaS platforms using JWTs for session management
- ●Microservice APIs with JWT-based service-to-service auth
- ●Mobile-app backends using JWTs as Bearer tokens
- ●Single-page applications storing JWTs in localStorage or cookies
- ●Identity providers and SSO systems
- ●GraphQL APIs authenticated with JWTs
- ●Custom-built auth on top of off-the-shelf libraries
If a feature reads `Authorization: Bearer ...`, `Cookie: session=ey...`, or any other JWT-style token, JWT attacks may live there.
8. Examples
Five realistic scenarios. Each is a small walkthrough, no characters.
Example 1. Unverified Signature
The feature. An app uses JWTs in cookies. The handler reads the role from the JWT.
The bug. `jwt.decode()` base64-decodes the payload without checking the signature. Any payload is accepted.
The attack step by step.
- ●Log in as a normal user. Capture the JWT.
- ●Decode the payload at jwt.io. Locate `"role":"user"`.
- ●Change it to `"role":"admin"`.
- ●Re-encode and replace the JWT in the cookie. Leave the signature alone (or even remove it).
- ●Send the request. Admin access granted.
Example 2. alg = none Acceptance
The feature. The server uses a JWT library that supports the `none` algorithm for unsigned tokens.
The bug. When the library sees `alg: none` in the header, it skips signature verification entirely.
The attack step by step.
- ●Capture a valid JWT.
- ●Edit the header to `{"alg":"none","typ":"JWT"}`.
- ●Edit the payload as desired.
- ●Strip the signature (leave the trailing dot).
- ●Send the modified token. Server accepts.
A common bypass when "none" is filtered as a string: use `None`, `NONE`, or `nOnE`.
Example 3. Weak HS256 Secret
The feature. The server signs tokens with HS256 and a short, guessable secret.
The bug. HS256 is HMAC with SHA-256. The secret is the password. A short or common secret can be brute-forced.
The attack step by step.
- ●Capture a valid JWT.
- ●Run hashcat:
- ●Hashcat tries each candidate, signs the header+payload, compares to the captured signature.
- ●A match means the secret is found. Hashcat prints it.
- ●Re-sign any desired payload using the discovered secret.
Example 4. jwk Header Injection
The feature. The server uses RS256 and allows the JWT to declare its own public key via the `jwk` header.
The bug. The server uses whatever public key is embedded in the JWT itself.
The attack step by step.
- ●Generate an RSA key pair locally.
- ●Build a forged JWT with the desired payload.
- ●Sign it with your private key.
- ●Embed your public key in the `jwk` header of the JWT.
- ●Send. Server verifies with your public key, signature matches, token accepted.
Burp's JWT Editor extension automates this via the "Attack ==> Embedded JWK" option.
Example 5. Algorithm Confusion (RS256 to HS256)
The feature. The server uses RS256 and exposes its public key at `/jwks.json`. The verification code uses a poorly-written library wrapper.
The bug. The code switches on the JWT's `alg` header, but always passes the same `key` (the RSA public key). When the attacker sets `alg: HS256`, the public key is used as an HMAC secret.
The attack step by step.
- ●Fetch the server's public key from `/jwks.json` (or `/.well-known/jwks.json`).
- ●Convert it to PEM format.
- ●Build a JWT with `alg: HS256` and the desired payload.
- ●Sign it with HMAC-SHA-256, using the PEM public key string as the HMAC secret.
- ●Send. The server's poorly-written verification uses the public key as the HMAC secret. The signature matches. Token accepted.
Each pattern appears in real disclosed reports. The mechanics never change.
9. Vulnerable Code
Node.js (jsonwebtoken) ==> decode vs verify confusion
What is wrong: `decode()` is parsing only. Use `verify()`:
Python (PyJWT) ==> none algorithm allowed
What is wrong: including `"none"` in `algorithms` means an attacker can submit an unsigned token.
Python (PyJWT) ==> verify_signature disabled
What is wrong: explicit opt-out of signature verification. Identical to using `decode` only.
Node.js (jsonwebtoken) ==> weak secret
What is wrong: a four-character common secret is brute-forced in milliseconds.
Java (Auth0 java-jwt) ==> Algorithm switch without enforcement
What is wrong: the algorithm is chosen from the token. Algorithm confusion attack succeeds.
Python (Flask) ==> jwk header trusted
What is wrong: the JWT carries the key the server will use to verify it. The attacker supplies their own key.
Node.js ==> jku trusted without allowlist
What is wrong: `jku` can be any URL. The attacker hosts their own key set and the server fetches it.
Python ==> kid used in path
What is wrong: `kid` is attacker-controlled. The attacker uses `../../dev/null` to make `key` an empty string, then signs the JWT with the empty secret.
Node.js ==> algorithms not pinned
What is wrong: omitting the `algorithms` argument allows the library to use whichever algorithm the token declares. Algorithm confusion possible.
Universal pattern across languages
Step 2, 3, and 4 are where every JWT bug is born. Every time.
10. Detection
Detection is the step where you confirm a JWT bug exists. Walk through each test in order.
Step 1. Find every place the app uses JWTs
- ●`Cookie:` headers (sometimes named `session`, `auth`, `token`, `jwt`, `access_token`).
- ●`Authorization: Bearer ...` headers.
- ●URL parameters (rarer, e.g. `?token=`).
- ●GraphQL operations carrying tokens.
- ●Custom headers like `x-access-token`, `x-auth-token`, `id-token`.
Step 2. Capture a valid token
Log in normally. Watch for any base64-looking string with two dots: `xxxx.yyyy.zzzz`. That is a JWT.
Step 3. Decode and inspect
Paste into https://jwt.io or Burp's JWT Editor. Note:
- ●`alg` value (HS256, RS256, etc).
- ●Whether `kid`, `jwk`, `jku`, `x5u`, `x5c` are present.
- ●Which claim identifies the user (`sub`, `user`, `email`).
- ●Which claim defines privilege (`role`, `isAdmin`, `permissions`, `scope`).
Step 4. Run the seven-attack-class checklist
For each captured token, try each class in sequence:
Burp Suite step by step
- ●Install the JWT Editor extension from BApp Store.
- ●Intercept a request containing a JWT.
- ●Send to Repeater.
- ●Click the JWT in the editor. The extension shows header and payload tabs.
- ●Edit the payload (e.g. change `role` to `admin`).
- ●Click "Attack" ==> select the attack class to try (Embedded JWK, JWK Set URL, Embedded JWK Header parameter injection, Sign with weak key, etc).
- ●Send.
jwt_tool
- ●Install: `git clone https://github.com/ticarpi/jwt_tool && pip3 install -r requirements.txt`
- ●Quick scan:
`-M pb` runs the playbook of standard JWT attacks. Output shows which succeeded.
hashcat brute force
For larger wordlists or quick scans, use `jwt.secrets.list`:
Indicators of a vulnerable JWT setup
- ●JWT header includes `kid`, `jwk`, `jku`, or `x5u`.
- ●Application uses different services with possibly inconsistent verification logic.
- ●Public-key endpoints visible at `/.well-known/jwks.json`, `/jwks.json`, `/auth/jwks`.
- ●Tokens still accepted after the published `exp` timestamp has passed.
- ●Microservices share a JWT issued by one but verified by another with different libraries.
- ●Open-source dependencies (jsonwebtoken, PyJWT, java-jwt, etc.) on versions with known CVEs.
Quick command-line detection script
If the printed token with `alg=none` is accepted by the server, you have a finding.
11. Exploitation
This section walks the seven PortSwigger lab patterns plus several auxiliary techniques. Each one is a complete, repeatable recipe.
Workflow
Attack 1. Unverified Signature (Apprentice)
Pattern: server calls `jwt.decode()` instead of `jwt.verify()`.
Lab: *JWT authentication bypass via unverified signature*.
Recipe:
- ●Log in. Capture the cookie containing the JWT.
- ●Decode the payload. Identify the claim that controls privilege.
- ●In Burp's JWT Editor: edit the payload. Change `"sub":"wiener"` to `"sub":"administrator"` (lab-specific).
- ●Leave the original signature in place (or remove it; both often work).
- ●Send the request to `/admin`. Response is 200 with admin content.
PortSwigger lab solution sketch:
- ●Replace the session cookie. Visit `/admin`. Visit `/admin/delete?username=carlos`. Lab solved.
Attack 2. alg=none (Apprentice)
Pattern: server accepts `alg=none` and skips signature verification.
Lab: *JWT authentication bypass via flawed signature verification*.
Recipe:
- ●Capture the cookie.
- ●In JWT Editor: change `"alg":"HS256"` to `"alg":"none"`.
- ●Edit the payload as needed (e.g. `"sub":"administrator"`).
- ●Strip the signature. Keep the trailing dot: `header.payload.`
- ●Send.
Case-variant bypass when "none" is filtered:
Try each. Some filters are case-sensitive string comparisons; mixed case bypasses them.
Attack 3. Weak HS256 Secret (Practitioner)
Pattern: server signs with HS256 using a short or common secret.
Lab: *JWT authentication bypass via weak signing key*.
Recipe:
- ●Capture the JWT.
- ●Run hashcat:
- ●Wait. On modern hardware this finishes in seconds for common secrets. Hashcat prints:
- ●In JWT Editor, generate a "New Symmetric Key" with the identified secret as the `k` value.
- ●Edit the payload. Change `sub` to `administrator`.
- ●Sign with the new symmetric key.
- ●Replace the cookie. Visit `/admin`. Solved.
Common weak secrets to try first:
Attack 4. jwk Header Injection (Practitioner)
Pattern: server uses any public key embedded in the `jwk` header.
Lab: *JWT authentication bypass via jwk header injection*.
Recipe:
- ●In JWT Editor Keys tab: click "New RSA Key" ==> Generate.
- ●Send the request to Repeater.
- ●Switch to the JSON Web Token tab.
- ●Edit the payload (e.g. `sub` to `administrator`).
- ●Click "Attack" ==> "Embedded JWK".
- ●Select your newly-generated RSA key.
- ●The extension embeds your public key in the `jwk` header, updates `kid`, and re-signs with your private key.
- ●Send. Server accepts.
Manual variant:
Re-sign with your private key.
Attack 5. jku Header Injection (Practitioner)
Pattern: server fetches `jku` URL without an allowlist.
Lab: *JWT authentication bypass via jku header injection*.
Recipe:
- ●In JWT Editor: generate a new RSA key.
- ●Export the JWK Set:
- ●Host it at a URL you control: `https://your-exploit-server/jwks.json`.
- ●Edit the JWT header:
- ●Edit payload. Sign with your private key. Send. Server fetches your JWKS, finds your key, verifies, accepts.
URL parsing bypass tricks (when the server requires the jku host to match an allowlist):
Attack 6. kid Path Traversal (Practitioner)
Pattern: server uses `kid` as a file path. Often combined with HS256.
Lab: *JWT authentication bypass via kid header path traversal*.
Recipe:
- ●Identify the JWT uses HS256.
- ●In JWT Editor: generate a "New Symmetric Key". Set the `k` value to an empty string (or base64-encoded empty string `""`).
- ●Edit the JWT header:
- ●Edit the payload. Set `sub` to `administrator`.
- ●Sign with the empty-secret symmetric key.
- ●Send. The server reads `/dev/null` (empty), uses the empty string as the HMAC secret, verifies the token (because you also signed with empty), accepts.
Other useful file paths:
Attack 7. Algorithm Confusion HS256/RS256 (Expert)
Pattern: server expects RS256 but the library switches to HS256 based on the `alg` header.
Lab: *JWT authentication bypass via algorithm confusion*.
Recipe (when the public key is exposed):
- ●Fetch the server's public key from `/.well-known/jwks.json`, `/jwks.json`, `/auth/jwks`, `/api/jwks`, `/keys`, `/security/jwks`, `/public-keys`.
- ●You see a JWK like:
- ●In JWT Editor Keys: click "New RSA Key" ==> paste the JWK ==> select "PEM" ==> copy the resulting PEM.
- ●Go to Burp Decoder ==> Base64-encode the PEM (note: keep newlines exactly as they appear).
- ●Back in JWT Editor Keys: click "New Symmetric Key" ==> Generate ==> replace the `k` value with the base64-encoded PEM.
- ●Save the key.
- ●Send the JWT to Repeater.
- ●Edit the payload (`sub` to `administrator`).
- ●Edit the header: `alg` ==> `HS256`.
- ●Sign with the symmetric key you just created.
- ●Send.
Attack 8. Algorithm Confusion with No Exposed Key (Expert)
Pattern: same as Attack 7, but `/jwks.json` is not exposed.
Lab: *JWT authentication bypass via algorithm confusion with no exposed key*.
Recipe:
- ●Collect two valid JWTs (log in twice as the same user, or once each as two test users).
- ●Use the `sig2n` tool to derive candidate public keys:
- ●The tool prints multiple "Found n with multiplier X" sections, each with a candidate x509 PEM and a tampered JWT signed with HS256 using that PEM as the secret.
- ●Test each tampered JWT against the server. Whichever returns 200 OK is the correct key.
- ●Once you know the correct base64-encoded PEM, use it as the symmetric key in JWT Editor.
- ●Forge any payload (e.g. `sub: administrator`).
- ●Sign with HS256 using that key.
- ●Send. Accepted.
How sig2n works (briefly):
The RSA signature for each JWT depends on the modulus `n`. Given two signed messages from the same key, sig2n solves the math to recover `n` (the public modulus). With `n` and the standard exponent `e=65537`, it reconstructs the public key in x509 and PKCS1 forms.
Auxiliary Techniques
Technique 9. cty Header Injection (XXE / Deserialization)
When signature verification is bypassed via any earlier attack, also try setting `cty` to enable downstream parsing attacks:
If the application parses the payload as XML (because `cty` says so), you may inject XXE payloads.
With this `cty`, a Java app may deserialize the payload, enabling deserialization attacks.
Technique 10. x5c X.509 Injection
The `x5c` header carries an X.509 certificate chain. Similar to `jwk` injection: embed your own certificate. The complexity of X.509 parsing has historically led to CVEs (CVE-2017-2800, CVE-2018-2633).
Technique 11. SQL Injection in kid
When `kid` is used to look up a key in a database:
If the SQL is concatenated, the attacker controls what the `kid` resolves to.
Technique 12. JKU URL Parsing Bypasses
When the server enforces "jku host must be anastech.com":
Each may fool different URL parsers.
Technique 13. Wildcard kid
Some libraries match `kid` patterns. A `kid` of `*` or `''` may match a default key.
Technique 14. Re-using JWTs across services
Microservice architectures often share a JWT signing key. A JWT obtained on one service may be valid on another with different (and stricter) authorization rules.
Technique 15. Expired token acceptance
Some implementations forget to verify `exp`. Send a long-expired token. If accepted, that is its own vulnerability.
Technique 16. Public-key endpoints with information disclosure
These often reveal the algorithm and key IDs, helping you choose the next attack.
These techniques cover the modern JWT hunter's toolkit. The seven PortSwigger labs map to attacks 1 through 8. The auxiliary techniques are for the harder targets.
12. Proof of Concept
Burp Suite step by step
Python PoC ==> Attack 1 (Unverified Signature)
Python PoC ==> Attack 2 (alg=none)
Python PoC ==> Attack 3 (Brute Force HS256)
Or just use hashcat (much faster):
Python PoC ==> Attack 7 (HS256/RS256 Confusion)
Python PoC ==> Attack 8 (sig2n)
The candidate whose tampered JWT returns 200 is the right public key. Use that PEM (the x509 variant from sig2n) as a symmetric key in JWT Editor and forge any payload you want with HS256.
Manual jwk Header PoC
jwt_tool Playbook
These PoCs cover every PortSwigger lab in this category.
13. Payloads
Standard public-key endpoints
alg = none variants
For each, build the token as `header.payload.` (trailing dot, no signature).
Common weak HS256 secrets
Use `jwt.secrets.list` from https://github.com/wallarm/jwt-secrets for a comprehensive list.
kid path traversal payloads
For each, sign the JWT with HMAC-SHA-256 using the empty string as the secret (or the predictable file content).
kid SQL injection payloads
jwk header template
jku header template
Host at `https://your-exploit-server/jwks.json`:
jku bypass payloads (URL parsing tricks)
x5u and x5c templates
cty header to enable downstream attacks
Standard malicious payloads
Always set `exp` to a far-future value to avoid timing issues:
14. Wordlists and Payload Libraries
- ●jwt_tool ==> https://github.com/ticarpi/jwt_tool ==> The reference all-in-one JWT testing tool. Includes attack playbook, brute force, key confusion.
- ●jwt-secrets / jwt.secrets.list ==> https://github.com/wallarm/jwt-secrets ==> Definitive HS256 secret wordlist.
- ●rsa_sign2n (sig2n) ==> https://github.com/silentsignal/rsa_sign2n ==> Derive RSA public key from two JWTs.
- ●portswigger/sig2n Docker image ==> https://hub.docker.com/r/portswigger/sig2n ==> One-command sig2n wrapper.
- ●JWT Editor (Burp BApp) ==> https://github.com/PortSwigger/jwt-editor ==> Official PortSwigger extension with all standard attacks.
- ●hashcat ==> https://github.com/hashcat/hashcat ==> Use `-m 16500` for HMAC-JWT cracking.
- ●jwt-cracker ==> https://github.com/lmammino/jwt-cracker ==> Node-based HS256 brute force.
- ●jwt-hack ==> https://github.com/hahwul/jwt-hack ==> All-in-one Go-based JWT toolkit.
- ●jose-util ==> CLI for the Go go-jose library, useful for one-off forging.
- ●jwt.io ==> https://jwt.io ==> Live decoder, encoder, and signer in the browser.
- ●PayloadsAllTheThings ==> JSON Web Token ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/JSON%20Web%20Token
- ●HackTricks ==> JWT ==> https://book.hacktricks.xyz/pentesting-web/hacking-jwt-json-web-tokens
- ●PortSwigger ==> JWT Attacks ==> https://portswigger.net/web-security/jwt
- ●PortSwigger ==> Algorithm Confusion Attacks ==> https://portswigger.net/web-security/jwt/algorithm-confusion
- ●OWASP JWT Cheat Sheet ==> https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html
- ●SecLists ==> JWT ==> https://github.com/danielmiessler/SecLists ==> includes alg-confusion and secret wordlists.
- ●Anas Magane Pentesting Notes ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP/JWT
- ●RFC 7519 (JWT) ==> https://datatracker.ietf.org/doc/html/rfc7519
- ●RFC 7515 (JWS) ==> https://datatracker.ietf.org/doc/html/rfc7515
- ●RFC 7517 (JWK) ==> https://datatracker.ietf.org/doc/html/rfc7517
- ●RFC 7518 (JWA) ==> https://datatracker.ietf.org/doc/html/rfc7518
15. Impact
- ●Privilege escalation. Change `role: user` to `role: admin`. The number-one impact.
- ●Account impersonation. Change `sub: anas` to `sub: carlos`. Become any user without their password.
- ●Authentication bypass. Forge a brand-new JWT for any account.
- ●Admin panel access. Most JWT bugs lead directly into admin endpoints with critical functionality.
- ●Mass account takeover. When the secret is found, the attacker can mint tokens for every user.
- ●Persistent backdoor. Mint a long-lived token with `exp` far in the future and `sub: administrator`.
- ●Lateral movement. If multiple microservices share a signing key, one compromise spreads.
- ●API abuse. APIs guarded by JWT-based scopes can be called with arbitrary scope claims.
- ●Refresh-token theft. Some flows let the attacker exchange a forged JWT for a real refresh token.
- ●Data exfiltration. Forged token plus admin endpoint typically equals full database read.
- ●Audit-trail forgery. Attacker actions appear as the impersonated user in logs.
- ●Compliance disaster. GDPR, HIPAA, PCI DSS, SOC 2 all care about authentication integrity.
A successful JWT attack is almost never a "low" severity finding. Most map to High or Critical.
16. Prevention
Vulnerable example
Secure example
Key changes:
- ●`verify`, not `decode`.
- ●`algorithms: ['RS256']` pins the expected algorithm so RS256/HS256 confusion is impossible.
- ●The verification key is hard-coded server-side; the JWT never tells the server which key to use.
- ●Issuer and audience are checked.
- ●Expiration is enforced (default in most libraries).
Eight Rules to Eliminate JWT Bugs
- ●Rule 1. Always call `verify`, never just `decode`.
- ●Rule 2. Pin the algorithm. Pass `algorithms: ['HS256']` or `algorithms: ['RS256']` explicitly. Never leave it open.
- ●Rule 3. For HS256, use a secret with at least 256 random bits. Generated with a CSPRNG. Stored in a secret manager.
- ●Rule 4. Never trust `kid`, `jwk`, `jku`, `x5u`, or `x5c` headers from the token. The server picks the verification key from a server-side source.
- ●Rule 5. When you must support `kid`, validate it against an exact-match allowlist. Sanitize against path traversal. Use parameterized queries if `kid` indexes a database.
- ●Rule 6. Validate `iss` (issuer) and `aud` (audience). Tokens issued for one service should not be valid on another.
- ●Rule 7. Enforce `exp` and `nbf`. Use a small clock tolerance, not minutes.
- ●Rule 8. Use a maintained library on a current version. Subscribe to security advisories for jsonwebtoken, PyJWT, java-jwt, jose, etc.
Developer checklist
Framework-specific safe usage
Node.js (jsonwebtoken):
Python (PyJWT):
Java (Auth0 java-jwt):
Go (golang-jwt):
Enterprise Mitigations
- ●Use a centralized JWT library wrapper so developers cannot accidentally call `decode()`.
- ●Run periodic JWT secret-strength audits on production by attempting hashcat against captured tokens.
- ●Use asymmetric algorithms (RS256, ES256) in production to keep HS256 brute force out of the picture.
- ●Rotate signing keys quarterly. Support key rotation via a server-controlled `kid` allowlist.
- ●Log all token verification failures with header details. Spikes mean someone is testing.
- ●Add a CI rule (Semgrep, CodeQL) that fails when `jwt.decode()` is called without `verify()` somewhere in the same call.
- ●Use Burp / DAST scanners with JWT plugins as part of release gates.
- ●For OAuth IdPs, expose only the keys you actively use at `/jwks.json`. Rotate often.
17. Real-World Cases
CVE-2022-23529 (jsonwebtoken Critical)
A vulnerability in the popular Node `jsonwebtoken` library allowed attackers who control the verification key to perform malicious operations. Patched in 9.0.0. Major because `jsonwebtoken` is one of the most-downloaded JWT libraries in the world.
CVE-2022-23539, CVE-2022-23540, CVE-2022-23541 (jsonwebtoken Insecure Defaults)
A trio of vulnerabilities disclosed at the same time, covering insecure default algorithms in `jsonwebtoken`'s `verify()` function. Each enabled forging tokens under specific conditions.
Auth0 Algorithm Confusion (Historical)
The original disclosure of HS256/RS256 algorithm confusion came from research against Auth0's own SDKs. The fix established the modern recommendation to pin `algorithms` explicitly.
PyJWT Historical Bypasses
PyJWT had several CVEs over its history relating to `alg: none` acceptance. The library now strictly disallows `none` unless the caller opts in.
Firebase JWT (PHP) RCE Chain
A chain involving a poorly-validated `kid` parameter and SQL injection in the Firebase PHP JWT library led to RCE in apps that used the kid as a SQL key lookup.
Atlassian Confluence Marketplace App JWT Misuse
Multiple Confluence Cloud marketplace apps used the host-issued JWT for inter-service auth but failed to validate `qsh` (query string hash) or `aud`. Reports valued at $3,000 to $15,000.
HackerOne ==> Slack JWT-Based ATO via Brute-Force
A bug bounty report on Slack documented a weak HS256 secret in a legacy service that allowed token forging.
HackerOne ==> Shopify Admin App JWT iss Confusion
A bug bounty report demonstrated cross-tenant access via JWT validation that did not check `iss`.
Imgur Spaces / Disqus Style App JWTs
Several smaller platforms had `alg: none` acceptance bugs in early years.
Modern (2024-2026) Pattern: Microservice JWT Replay
Microservice architectures sharing a signing key across multiple services regularly produce findings where a JWT for a low-privilege service is replayed against a higher-privilege service that does not check `aud`.
Lessons across these cases:
- ●Battle-tested libraries still ship security bugs. Keep them up to date.
- ●The default behavior of many libraries used to be unsafe; modern versions enforce `algorithms` and reject `none` by default. Old code on old library versions remains a target.
- ●Even when the library is correct, custom wrapper code often re-introduces the bugs (decode vs verify, alg switching by header).
- ●The `aud` and `iss` claims are routinely under-validated. Always check them.
- ●Bug bounty payouts for full JWT-driven ATO sit in the $5,000 to $50,000+ range.
18. References
- ●PortSwigger Web Security Academy ==> JWT Attacks ==> https://portswigger.net/web-security/jwt
- ●PortSwigger Web Security Academy ==> Algorithm Confusion ==> https://portswigger.net/web-security/jwt/algorithm-confusion
- ●MITRE CWE-345 ==> https://cwe.mitre.org/data/definitions/345.html (Insufficient Verification of Data Authenticity)
- ●MITRE CWE-347 ==> https://cwe.mitre.org/data/definitions/347.html (Improper Verification of Cryptographic Signature)
- ●MITRE CWE-327 ==> https://cwe.mitre.org/data/definitions/327.html (Use of a Broken or Risky Cryptographic Algorithm)
- ●OWASP JWT Cheat Sheet ==> https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html
- ●PayloadsAllTheThings ==> JSON Web Token ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/JSON%20Web%20Token
- ●HackTricks ==> JWT ==> https://book.hacktricks.xyz/pentesting-web/hacking-jwt-json-web-tokens
- ●jwt_tool ==> https://github.com/ticarpi/jwt_tool
- ●jwt.io decoder ==> https://jwt.io
- ●rsa_sign2n ==> https://github.com/silentsignal/rsa_sign2n
- ●jwt-secrets / jwt.secrets.list ==> https://github.com/wallarm/jwt-secrets
- ●JWT Editor for Burp ==> https://github.com/PortSwigger/jwt-editor
- ●jwt-hack ==> https://github.com/hahwul/jwt-hack
- ●RFC 7519 (JWT) ==> https://datatracker.ietf.org/doc/html/rfc7519
- ●RFC 7515 (JWS) ==> https://datatracker.ietf.org/doc/html/rfc7515
- ●RFC 7516 (JWE) ==> https://datatracker.ietf.org/doc/html/rfc7516
- ●RFC 7517 (JWK) ==> https://datatracker.ietf.org/doc/html/rfc7517
- ●RFC 7518 (JWA Algorithms) ==> https://datatracker.ietf.org/doc/html/rfc7518
- ●CVE-2022-23529 jsonwebtoken ==> https://nvd.nist.gov/vuln/detail/CVE-2022-23529
- ●Auth0 jsonwebtoken Security Advisories ==> https://github.com/auth0/node-jsonwebtoken/security/advisories
- ●PortSwigger sig2n Docker ==> https://hub.docker.com/r/portswigger/sig2n
- ●Anas Magane Pentesting Notes ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP/JWT
19. Practical Labs
SOON.
The ANAS EDUCATION lab environment for JWT is currently being built. You will soon practice:
- ●Unverified signature on a fake bank dashboard
- ●`alg: none` bypass on a profile-update API
- ●Weak HS256 secret brute force with hashcat
- ●jwk header injection against a misconfigured RS256 verifier
- ●jku header injection with an attacker-hosted JWK Set
- ●kid path traversal to `/dev/null`
- ●SQL injection via kid in a database-backed key store
- ●Algorithm confusion RS256 to HS256 with exposed public key
- ●Algorithm confusion using sig2n with no exposed key
- ●cty header XXE on a misconfigured downstream parser
- ●Token replay across microservices missing `aud` check
- ●Long-lived backdoor token with `exp` far in the future
In the meantime, practice on PortSwigger Web Security Academy labs:
- ●APPRENTICE: JWT authentication bypass via unverified signature
- ●APPRENTICE: JWT authentication bypass via flawed signature verification (alg=none)
- ●PRACTITIONER: JWT authentication bypass via weak signing key
- ●PRACTITIONER: JWT authentication bypass via jwk header injection
- ●PRACTITIONER: JWT authentication bypass via jku header injection
- ●PRACTITIONER: JWT authentication bypass via kid header path traversal
- ●EXPERT: JWT authentication bypass via algorithm confusion
- ●EXPERT: JWT authentication bypass via algorithm confusion with no exposed key
Stay tuned.
20. Cheat Sheet
21. Exam (30 Questions)
Format: Multiple Choice. Platform randomly selects 20. Scoring: 0 to 13 fail, 14 to 15 retry, 16 to 20 pass.
Q1. A JWT consists of which three parts? A. Username, password, session B. Header, payload, signature C. URL, body, cookie D. Client, server, network Answer: B.
Q2. Each JWT part is encoded with: A. AES-256 B. Base64url C. SHA-256 D. ROT13 Answer: B.
Q3. The payload of a JWT is: A. Encrypted by default B. Just base64-encoded JSON, readable by anyone C. Hashed with SHA-512 D. Compressed with gzip Answer: B.
Q4. The function `jwt.decode()` in most libraries: A. Verifies the signature B. Only base64-decodes; does NOT verify the signature C. Signs the token D. Encrypts the payload Answer: B.
Q5. Which CWE primarily covers JWT signature bypass bugs? A. CWE-79 B. CWE-89 C. CWE-345 / CWE-347 D. CWE-22 Answer: C.
Q6. When the header is `{"alg":"none"}`, the signature is: A. RSA-signed B. Not required; some libraries skip verification entirely C. Always required D. Encrypted with AES Answer: B.
Q7. Case variants for the alg=none bypass include: A. `none`, `None`, `NONE`, `nOnE` B. Only lowercase `none` C. Only uppercase `NONE` D. None of these Answer: A.
Q8. HS256 uses what kind of key? A. Asymmetric (private/public) B. Symmetric (a shared secret) C. No key D. AES key Answer: B.
Q9. What is the hashcat mode for cracking JWTs signed with HS256? A. 0 B. 100 C. 16500 D. 1800 Answer: C.
Q10. The `jwk` header parameter: A. Points to a JWK Set URL B. Embeds a JSON Web Key directly inside the JWT C. Sets the issuer D. Sets the audience Answer: B.
Q11. The `jku` header parameter: A. Embeds a public key B. Provides a URL where the server can fetch a JWK Set C. Sets the issuer D. Sets the expiration Answer: B.
Q12. The `kid` header parameter: A. Identifies which key the server should use B. Always equals "key" C. Is the secret itself D. Must be a UUID Answer: A.
Q13. A `kid` set to `../../dev/null` exploits: A. SQL injection B. Path traversal, combined with the empty content of /dev/null acting as an empty HMAC secret C. CSRF D. SSRF Answer: B.
Q14. Algorithm confusion HS256 vs RS256 exploits: A. RSA factoring B. The server using the public key as an HMAC secret when an attacker sets alg=HS256 C. SQL injection D. Path traversal Answer: B.
Q15. To perform algorithm confusion when no key is exposed, you can use: A. nmap B. sig2n (rsa_sign2n) with two captured tokens C. sqlmap D. ffuf Answer: B.
Q16. A standard endpoint that exposes the public JWKS is: A. `/admin/login` B. `/.well-known/jwks.json` C. `/static/main.css` D. `/api/users` Answer: B.
Q17. The most reliable defense against algorithm confusion is: A. Use HS256 only B. Pin the expected algorithm explicitly in `algorithms: ['RS256']` C. Hide the public key D. Use base64url Answer: B.
Q18. Which library function in Node.js is safer to use? A. `jwt.decode(token)` B. `jwt.verify(token, key, { algorithms: ['RS256'] })` C. `jwt.sign(token)` D. `jwt.parse(token)` Answer: B.
Q19. Burp's JWT Editor "Attack ==> Embedded JWK" performs: A. Algorithm confusion B. jwk header injection C. Brute force D. SQL injection Answer: B.
Q20. Which is true about JWT payloads? A. They are encrypted with the server's private key B. They are only base64-encoded JSON and readable by anyone C. They are hashed and unrecoverable D. They are stored on the server Answer: B.
Q21. A weak HS256 secret of `"secret123"` can be cracked in approximately: A. Years B. Months C. Hours D. Seconds with hashcat on modern hardware Answer: D.
Q22. Which PortSwigger lab requires `sig2n`? A. JWT authentication bypass via unverified signature B. JWT authentication bypass via weak signing key C. JWT authentication bypass via algorithm confusion with no exposed key D. JWT authentication bypass via flawed signature verification Answer: C.
Q23. The Authorization header carrying a JWT looks like: A. `Authorization: <jwt>` B. `Authorization: Basic <jwt>` C. `Authorization: Bearer <jwt>` D. `Authorization: Cookie <jwt>` Answer: C.
Q24. A JWT with the trailing dot but no signature (e.g. `header.payload.`) is: A. Always invalid B. Valid only when alg=none and the server accepts that C. Used for encryption D. The standard format Answer: B.
Q25. Which library option in PyJWT bypasses signature verification? A. `algorithms=["HS256"]` B. `options={"verify_signature": False}` C. `audience="anastech"` D. `issuer="anastech"` Answer: B.
Q26. To protect against `kid` path traversal, the safe pattern is: A. Concatenate `kid` into the file path B. Use an exact-match allowlist of acceptable `kid` values C. URL-decode `kid` first D. Hash `kid` and use the hash Answer: B.
Q27. The `cty` header parameter can enable: A. CSRF B. XXE or deserialization attacks on the payload when signature is also bypassed C. SQL injection D. SSRF Answer: B.
Q28. Which is NOT a recommended prevention? A. Pin algorithms explicitly B. Use a strong random secret stored in a secret manager C. Trust `kid`, `jwk`, `jku` from the token D. Verify iss and aud Answer: C.
Q29. Why does the `aud` (audience) claim matter? A. It encrypts the token B. It binds a token to a specific recipient service, preventing cross-service replay C. It expires the token D. It signs the token Answer: B.
Q30. The MOST important takeaway about JWT: A. JWTs are unbreakable B. A JWT is only as secure as the verification of its signature; pin algorithms, validate header keys server-side, never trust attacker-controlled fields C. JWTs are encrypted by default D. JWTs prevent CSRF Answer: B.
22. Certificate Requirements
To earn the ANAS EDUCATION JWT Attacks Certificate, the student must:
- ●Complete every lesson in this module.
- ●Complete all practical labs once released.
- ●Pass the exam with at least 16 out of 20.
Only then will the course be marked complete on the student dashboard.
23. Important Notes
Common Beginner Mistakes
- ●Confusing `decode()` with `verify()`. Always check which one the target uses.
- ●Forgetting that the JWT payload is just base64. Never put secrets in the payload.
- ●Trying only one attack class. Test all seven systematically.
- ●Skipping case variants of `none` (None, NONE, nOnE).
- ●Not testing every endpoint with the forged token. Sometimes only `/admin` checks the role.
- ●Forgetting to update `exp` to a far-future value.
- ●Forgetting to URL-encode `+` and `/` in JWTs sent through query strings.
Pentester Tips
- ●Capture multiple JWTs from different users; comparing them often reveals which claims matter.
- ●Always check `/.well-known/jwks.json` and similar endpoints for the public key.
- ●When testing in Burp, use Repeater with the JWT Editor extension; switching tabs preserves the token between sends.
- ●For `kid` traversal, also try Windows-style paths (`..\\dev\\null`) on Windows servers.
- ●For weak-secret brute force, start with `jwt.secrets.list` from wallarm.
Bug Bounty Tips
- ●JWT attacks pay $1,500 to $50,000+ depending on impact.
- ●Full ATO via algorithm confusion is consistently top-payer.
- ●SaaS platforms with multi-tenant JWTs are gold mines for `iss` and `aud` confusion.
- ●Microservice architectures sharing one signing key magnify impact.
- ●Document the exact verification call (`verify` vs `decode`, `algorithms=...`) in your report.
Red Team Notes
- ●Forged long-lived JWTs are excellent persistence. Set `exp: 9999999999`.
- ●A leaked HS256 secret from a public Git repo or CI log is a one-shot kill.
- ●JWT validation logs are noisy enough that a few forgery attempts blend in.
- ●Cloud functions and serverless apps often re-deploy with the same JWT secret, defeating rotation.
Real-World Advice
- ●The `kid` parameter is a magnet for bugs. Always test it for path traversal, SQL injection, and command injection.
- ●Even if a single service is secure, downstream microservices may share the key with weaker checks. Probe each.
- ●JWT libraries on package managers ship with insecure defaults that get fixed quietly. Audit the version in production.
- ●Logging the JWT in plain text (in error logs, request logs, debug pages) is itself a vulnerability.
- ●When `aud` is missing from issued tokens, every relying party trusts every token.
Things to Remember During Exams
- ●JWT = Header.Payload.Signature, all base64url.
- ●CWE-345 (auth), CWE-347 (signature), CWE-327 (algorithm).
- ●`verify` good, `decode` alone bad.
- ●hashcat `-m 16500` for HS256.
- ●Algorithm confusion uses the public key as the HMAC secret.
- ●sig2n derives the public key from two JWTs.
Things to Remember During Real Assessments
- ●Get explicit permission. JWT forging is privilege escalation; treat it that way.
- ●Use a non-destructive payload (e.g. read-only admin endpoint) first.
- ●Capture the full HTTP request and response for the report.
- ●Decode and document the forged token side-by-side with the original.
- ●Save the secret if you cracked one; report it as a separate finding.
- ●Clean up: revert any state changes made with the forged token.
Frequently Confused Concepts
- ●JWT vs Session Cookie. Session is server-stored; JWT is client-stored and self-contained.
- ●JWT vs JWS vs JWE. JWT is the format. JWS adds signature. JWE adds encryption.
- ●decode vs verify. decode reads; verify checks the signature.
- ●HS256 vs RS256. HS256 is symmetric (shared secret); RS256 is asymmetric (private/public).
- ●alg=none vs missing signature. "none" means the library is allowed to skip verification; a missing signature usually means the parser refuses.
- ●Public key vs JWKS. The public key is one key; JWKS is a set of keys exposed at a URL.
Interview Tips
- ●Be ready to draw the three parts of a JWT from memory.
- ●Explain why the payload is readable but trustworthy: trust = signature, not encoding.
- ●Walk through alg=none and algorithm confusion as two distinct attacks.
- ●Mention the seven PortSwigger labs as a study path.
- ●Cite hashcat mode 16500 and sig2n by name.
- ●Finish with prevention: pin algorithm, validate iss/aud/exp, never trust header keys.
Key Takeaways
- ●A JWT is a piece of state the server gave to the client and trusts when it comes back. Trust depends entirely on signature verification.
- ●The seven attack classes (unverified, none, weak secret, jwk, jku, kid, alg confusion) cover almost every real-world JWT bug.
- ●The bug class is universal across every language and framework. The library matters less than how it is called.
- ●Detection is one habit: decode every JWT you see in any traffic capture.
- ●The fix is one architectural rule: the server, not the token, picks the verification key and the verification algorithm.
24. Final Word from Your Instructor
JWTs are little contracts. The server signs them. The client carries them. The server trusts what it reads back.
That trust is the whole story.
If the trust is well-anchored ==> signature verified, algorithm pinned, key controlled server-side, key references ignored from the token ==> JWTs are an elegant, scalable design.
If any piece of that trust is leaky ==> decode used in place of verify, alg=none accepted, weak secret, jwk/jku honored, kid trusted ==> JWTs become a free authentication bypass.
Every time a developer writes:
A new JWT bug is born somewhere in the world.
Every time someone changes `"role": "user"` to `"role": "admin"` and the server says "welcome", a new bounty story is born.
Your job is to look at any `Authorization: Bearer` header and ask three questions:
- ●Who signed this?
- ●Who is supposed to verify it?
- ●What key are they using, and where does that key come from?
When you see an `alg` header, ask: "Could the attacker change this?"
When you see a `kid` header, ask: "Where does this name resolve?"
When you see a `jwk` or `jku` header, ask: "Does the server trust this without an allowlist?"
When you see `HS256`, ask: "What is the secret? Is it strong? Is it leaked anywhere on GitHub?"
When you see `RS256`, ask: "Where is the public key? Can the attacker swap algorithms?"
If the answer to any of those takes you to a place where attacker input controls the verification step, you have found a bug worth thousands of dollars.
The seven PortSwigger labs are your training ground. The eighth (`sig2n`) is the boss fight. The mindset is the same throughout: a JWT is a string the user can edit. The signature is the only protection. Break the signature, you break the server.
The hashcat command (`-m 16500`) is one of the most reliable wins in modern bug bounty. Memorize it.
The algorithm confusion chain is one of the cleanest critical-severity findings you can write. Memorize it.
The `kid` traversal trick is the rarely-tested classic. Memorize it.
- ●Welcome to the world where a single base64 string decides who is admin.
- ●Go hunt.