This chapter covers JSON Web Token (JWT) token attacks, a critical topic for the PT0-002 exam under Domain 3.2 (Attacks Exploits). JWT is widely used for authentication and authorization in modern web applications, and vulnerabilities in their implementation can lead to severe security breaches. Approximately 5-8% of exam questions touch on JWT attacks, focusing on exploitation techniques such as algorithm confusion, none algorithm attacks, and secret key cracking. Mastering these attacks is essential for any penetration tester assessing web applications.
Jump to a section
A JWT is like a company ID badge issued to an employee after they log in at the front desk. The badge has three parts: a visible front (header) showing the badge type and format, a photo and ID number (payload) identifying the employee and their access level (e.g., 'floor 5 access'), and a holographic seal (signature) that proves the badge was issued by the company and hasn't been altered. When the employee swipes into a secure area, the guard checks the hologram using a special scanner that verifies the signature with the company's secret key. If the hologram is missing or doesn't match, the guard denies entry. An attacker could try to peel off the photo and replace it with their own (tampering with the payload) but that would break the hologram because the seal covers the photo. However, if the guard doesn't check the hologram at all (no signature verification), the attacker could simply swap photos. Worse, if the badge has a 'none' hologram option and the guard accepts it, the attacker can create a fake badge with no seal. Similarly, if the guard uses a public key that is actually known to everyone, the attacker could forge the hologram. This mirrors JWT attacks: none algorithm, algorithm confusion, weak secret cracking, and payload tampering when verification is missing.
What is JWT and Why Does It Exist?
JSON Web Token (JWT) is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. It is commonly used for authentication and authorization in RESTful APIs and single sign-on (SSO) systems. The primary advantage of JWT is that it is stateless: the server does not need to store session data; all necessary information is embedded in the token itself. However, this statelessness also introduces unique attack vectors if the token is not properly validated.
JWT Structure
A JWT consists of three parts separated by dots: Header.Payload.Signature.
- Header: Contains metadata about the token, such as the signing algorithm (e.g., HS256, RS256) and token type (JWT). Example:
{
"alg": "HS256",
"typ": "JWT"
}- Payload: Contains claims (statements about the user and additional data). Common claims include:
- sub (subject): user ID
- iat (issued at): timestamp
- exp (expiration): timestamp
- admin: boolean flag for admin privileges
Example:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022,
"exp": 1516242622
}Signature: Generated by taking the base64url-encoded header and payload, concatenating them with a dot, and signing the result with a secret key (HMAC) or a private key (RSA/ECDSA). The signature ensures the token has not been tampered with.
How JWT Works Internally
Authentication: User logs in with credentials. Server validates credentials and creates a JWT with the user's identity and permissions. The server signs the token and returns it to the client.
Authorization: Client sends the JWT in the Authorization header (typically Bearer <token>) with each API request.
Verification: Server receives the token, extracts the header and payload, recomputes the signature using the secret/public key, and compares it to the provided signature. If they match, the token is valid. The server then reads the payload to authorize the request.
Key Components, Values, Defaults, and Timers
- Algorithms: The alg header parameter specifies the algorithm. Common values:
- HS256: HMAC with SHA-256 (symmetric, same key for signing and verification)
- RS256: RSA with SHA-256 (asymmetric, private key signs, public key verifies)
- ES256: ECDSA with P-256 and SHA-256
- none: No signature (used only in legacy or debugging, should never be accepted in production)
- Secret Key: For HMAC, the secret must be kept confidential. Default length should be at least 256 bits (32 bytes) for HS256.
- Public/Private Key Pair: For RSA/ECDSA, the private key signs, the public key verifies. The public key is often distributed to verifying servers.
- Expiration (`exp`): Standard claim that specifies when the token expires. Servers must check this timestamp and reject tokens past expiration.
- Issued At (`iat`): Timestamp when token was issued. Can be used to enforce token freshness.
- Not Before (`nbf`): Timestamp before which token is not valid.
- JWT ID (`jti`): Unique identifier for the token, useful for preventing replay attacks.
Configuration and Verification Commands
Penetration testers often use tools like jwt_tool, jwt-cracker, and pyjwt to analyze and exploit JWT. Common commands:
Decode JWT: jwt_tool <token> - Decodes and displays header and payload.
Crack HMAC secret: jwt_tool <token> -C -d /usr/share/wordlists/rockyou.txt - Attempts to crack the secret using a wordlist.
Modify payload and sign with known secret: jwt_tool <token> -T -S hs256 -p <secret> - Modifies payload and re-signs with provided secret.
None algorithm attack: jwt_tool <token> -X a - Changes algorithm to none and removes signature.
Algorithm confusion (RS256 to HS256): jwt_tool <token> -X k -pk <public_key_file> - Converts RS256 token to HS256 using the public key as the HMAC secret.
How JWT Interacts with Related Technologies
JWT is often used with OAuth 2.0 and OpenID Connect. In OAuth 2.0, JWT can be used as an access token (JWT access token) or as an ID token (OpenID Connect). The authorization server issues the JWT, and the resource server verifies it. Common vulnerabilities arise when the resource server does not properly validate the token's signature or algorithm, allowing attackers to forge tokens. Additionally, JWT may be stored in browser local storage or cookies, leading to XSS or CSRF attacks if not handled securely.
JWT Attack Vectors
None Algorithm Attack: If the server accepts tokens with alg: none, the attacker can modify the payload and remove the signature, creating a valid token without knowing the secret. The server must explicitly reject none algorithm.
Algorithm Confusion Attack: The attacker changes the algorithm from RS256 (asymmetric) to HS256 (symmetric). If the server's code does not check the algorithm and uses the same key for both signing and verification, the attacker can use the public key (which is often accessible) as the HMAC secret to sign a forged token. This occurs because the server uses the public key to verify an HMAC signature, which is essentially treating the public key as a symmetric secret.
Weak HMAC Secret: If the HMAC secret is weak (e.g., common password), the attacker can crack it offline using a wordlist. Once cracked, the attacker can forge arbitrary tokens.
Timing Attacks: If signature verification is not constant-time, an attacker may be able to brute-force the signature byte-by-byte using timing differences. However, this is less common in practice.
Key Confusion with JWK Header: Some servers accept a jwk (JSON Web Key) header containing the public key. An attacker can inject their own public key and sign the token with their private key. The server must not trust user-supplied keys.
Kid Header Injection: The kid (key ID) header can be used to point to a file or database entry. If not validated, an attacker can manipulate kid to perform path traversal or SQL injection.
Mitigations
Always validate the algorithm against an expected list. Reject none and any algorithm not in the list.
Use separate key types for different algorithms. Do not use the same variable for symmetric and asymmetric keys.
Use strong secrets for HMAC (at least 256 bits of entropy).
Do not accept jwk or jku headers from untrusted sources.
Validate kid against a whitelist or ensure it cannot be used for injection.
Always check exp and nbf claims.
Use short token expiration times and implement token revocation mechanisms.
Identify JWT in Request
The first step is to locate the JWT in the HTTP request. Typically, JWT is sent in the Authorization header as 'Bearer <token>'. However, it may also be in cookies, URL parameters, or POST body. Use a proxy like Burp Suite to intercept requests. Look for a base64url-encoded string with three parts separated by dots. Decode the token using a tool like jwt.io or jwt_tool to inspect the header and payload. This reveals the algorithm and claims. Document the token for further analysis.
Check for None Algorithm
Modify the token's header to set `alg` to `none` and remove the signature part entirely. Send the modified token to the server. If the server accepts it, this is a critical vulnerability. The server likely has a flawed validation that does not enforce signature verification when algorithm is `none`. In the real world, this often happens because developers use libraries that default to accepting `none` for debugging and forget to disable it in production. On the exam, this is a common attack to identify.
Attempt Algorithm Confusion
If the token uses RS256 (asymmetric), try to change the algorithm to HS256. Obtain the server's public key (often exposed via well-known endpoints like `/.well-known/jwks.json`). Use the public key as the HMAC secret to sign a forged token with `alg: HS256`. Send the modified token. If the server verifies using the public key as the HMAC secret (due to code that uses the same variable for both), the attack succeeds. This is a classic confusion between symmetric and asymmetric verification. The exam expects you to know that the public key is not secret and can be used to forge tokens if the server misuses it.
Crack Weak HMAC Secret
If the token uses HS256, attempt to crack the secret using a wordlist. Use a tool like `jwt-cracker` or `hashcat` with mode 16500 (JWT). The secret is used to compute the HMAC signature. By brute-forcing common passwords, you may recover the secret. Once cracked, you can forge tokens with arbitrary payloads. On the exam, they may give you a token with a weak secret and ask you to determine the secret or the impact. Common weak secrets include 'secret', 'password', or '123456'.
Exploit Kid Injection
If the header contains a `kid` (key ID) parameter, check if it is used to fetch a key from a file or database. Try modifying `kid` to perform path traversal (e.g., `../../../../etc/passwd`) or SQL injection. If the server returns an error or behaves differently, it may be vulnerable. In some implementations, the `kid` value is used in a file read operation, allowing arbitrary file read. On the exam, you may need to identify that `kid` injection can lead to remote code execution or information disclosure.
Enterprise Scenario 1: Microservices Authentication
A large e-commerce platform uses JWT for authentication across dozens of microservices. The authentication service issues RS256-signed tokens after user login. Each microservice verifies the token using a public key obtained from a central JWKS endpoint. The problem: one microservice's JWT library was configured to accept tokens signed with any algorithm, including none. A penetration tester discovered this by sending a token with alg: none and arbitrary payload. The microservice granted admin access. The fix: upgrade the library and configure it to only accept RS256. Additionally, implement strict validation of the alg header against a whitelist. In production, this type of vulnerability is common in legacy or hastily written services.
Enterprise Scenario 2: Single Sign-On (SSO) with OAuth 2.0
A company uses an SSO provider that issues JWT ID tokens. The resource server (an internal application) validates the token by fetching the public key from the provider's JWKS URI. However, the developer accidentally used the same variable for both HMAC secret and RSA public key. An attacker obtained the public key (easily accessible from the JWKS endpoint) and performed an algorithm confusion attack. They changed the algorithm from RS256 to HS256 and signed a forged token using the public key as the HMAC secret. The server accepted the token because it used the same key variable for verification. The attacker gained access to sensitive data. This scenario highlights the importance of type-checking and using separate key stores.
Enterprise Scenario 3: Mobile App API
A mobile banking app uses JWT for API authentication. The JWT is stored in the app's local storage and sent with each request. The token uses HS256 with a secret derived from the app's package name and version. An attacker decompiled the app, extracted the secret generation logic, and cracked the secret by brute-forcing common package names. Once the secret was known, the attacker forged tokens with elevated privileges. The fix: use a strong, unique secret per installation (e.g., derived from user password) and implement token expiration. Additionally, use asymmetric signing so the secret is not shared across all clients.
What PT0-002 Tests on JWT Attacks
The exam objective 3.2 (Attacks Exploits) includes JWT attacks under 'Web application attacks'. Specifically, you must understand how to exploit JWT vulnerabilities: none algorithm, algorithm confusion, weak secret cracking, and key injection. The exam expects you to identify the attack type from a description or token snippet, and know the mitigation. You will not be asked to crack a secret manually, but you may need to recognize the steps.
Common Wrong Answers and Why Candidates Choose Them
'The token uses RS256, so it is secure' – Wrong. RS256 is secure only if the private key is protected and the server validates the algorithm correctly. Algorithm confusion can bypass RS256.
'The none algorithm is always rejected' – Wrong. Many libraries accept none by default unless explicitly configured to reject it. Candidates often assume it is always blocked.
'The public key is secret' – Wrong. Public key is, by definition, public. Candidates confuse it with the private key.
'JWT tokens are encrypted' – Wrong. JWT is signed, not encrypted (unless using JWE). Payload is base64url-encoded, not encrypted. Anyone can decode it.
Specific Numbers, Values, and Terms That Appear on the Exam
Algorithm values: HS256, RS256, ES256, none
Header parameters: alg, typ, kid, jwk, jku
Claims: sub, iat, exp, nbf, jti, admin
Tools: jwt_tool, jwt-cracker, Burp Suite
Attack names: None algorithm attack, algorithm confusion attack, key injection, kid injection
Edge Cases and Exceptions the Exam Loves to Test
Token without signature: If the signature is missing but the algorithm is none, it's a none attack. But if the signature is missing and algorithm is HS256, it's invalid.
Multiple signatures: Some JWTs have multiple signatures; the exam may test that only the first signature is verified.
JWK header with embedded key: If the server trusts the jwk header, an attacker can inject their own public key.
`kid` with SQL injection: If kid is used in a database query, it can lead to SQLi.
How to Eliminate Wrong Answers Using the Underlying Mechanism
If a question describes a token with alg: none and no signature, the attack is 'none algorithm attack'. Eliminate any answer that says 'algorithm confusion' because that requires changing the algorithm from asymmetric to symmetric.
If a question mentions 'public key' and 'HMAC secret', the attack is 'algorithm confusion'. Eliminate 'weak secret cracking' because that requires a symmetric token.
If a question describes brute-forcing a secret, it's 'weak HMAC secret'. Eliminate 'none algorithm' because that doesn't involve cracking.
If a question mentions kid pointing to a file, it's 'kid injection'. Eliminate 'JWK injection' because that involves the jwk header.
JWT consists of three parts: Header.Payload.Signature, all base64url-encoded.
The 'none' algorithm attack works if the server does not reject tokens with 'alg: none' and no signature.
Algorithm confusion attack changes RS256 to HS256 using the public key as the HMAC secret.
Weak HMAC secrets can be cracked using wordlists (e.g., rockyou.txt).
The 'kid' header can be manipulated for path traversal or SQL injection.
Always validate the algorithm against a whitelist; never trust user-supplied JWK or jku.
JWT does not encrypt data; payload is readable by anyone who decodes it.
Common tools for JWT attacks: jwt_tool, jwt-cracker, Burp Suite.
These come up on the exam all the time. Here's how to tell them apart.
HMAC (HS256)
Symmetric: same secret key for signing and verification.
Secret must be kept confidential on both server and any verifying party.
Faster than RSA for signing and verification.
Vulnerable to weak secret cracking if secret is guessable.
Algorithm confusion attack can use public key as secret if server misconfigured.
RSA (RS256)
Asymmetric: private key signs, public key verifies.
Public key can be shared openly; private key must be secret.
Slower than HMAC, but allows multiple verifiers without sharing secret.
Vulnerable to algorithm confusion if server uses same variable for public key and HMAC secret.
Public key can be obtained from JWKS endpoint, enabling forgery if confusion exists.
Mistake
JWT tokens are encrypted and cannot be read by attackers.
Correct
JWT is only base64url-encoded, not encrypted. Anyone with the token can decode the header and payload using a simple base64 decoder. The signature is for integrity, not confidentiality. Sensitive data should not be placed in the payload.
Mistake
The 'alg: none' attack is always prevented by modern JWT libraries.
Correct
Many libraries still accept 'none' by default for backward compatibility. For example, older versions of `pyjwt` and `jsonwebtoken` (Node.js) accept 'none' unless explicitly configured to reject it. Developers often forget to disable it.
Mistake
Algorithm confusion only works if the server uses the same key for both HMAC and RSA.
Correct
Algorithm confusion exploits the fact that the server uses the same variable to hold the secret (for HMAC) and the public key (for RSA). If the code does not differentiate, the attacker can use the public key as the HMAC secret. The key itself is the same variable, not necessarily the same key type.
Mistake
The 'kid' header is only used to identify the key and is safe to trust.
Correct
If the server uses 'kid' to fetch a key from a file or database without proper sanitization, it can lead to path traversal or SQL injection. Attackers can manipulate 'kid' to read arbitrary files or execute SQL commands.
Mistake
JWTs with RS256 are immune to none algorithm attacks.
Correct
If the server's verification code does not check the algorithm, an attacker can change the algorithm from RS256 to 'none' and remove the signature. The server may still accept it if it only verifies the signature when the algorithm is not 'none'.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
To detect a none algorithm vulnerability, intercept the JWT and modify the header to set `"alg": "none"` and remove the signature part (everything after the second dot). Send the modified token to the server. If the server accepts it and processes the request, it is vulnerable. You can use Burp Suite or `jwt_tool` with the `-X a` flag to automate this. On the exam, you may be given a scenario where a token with `alg: none` is accepted, indicating the vulnerability.
JWT (JSON Web Token) is a signed token (integrity) but not encrypted. Anyone can decode the payload. JWE (JSON Web Encryption) is an encrypted token that provides confidentiality. The payload is encrypted and can only be read by the intended recipient. JWE uses a Content Encryption Key (CEK) and is more complex. On the exam, know that JWT is for signing, JWE is for encryption. A common trap is assuming JWT is encrypted.
Yes, algorithm confusion can also target ECDSA (ES256) tokens. The attack works similarly: change the algorithm to HS256 and use the public key (which is accessible) as the HMAC secret. However, ECDSA public keys are typically in a different format (e.g., DER or JWK). The attack is less common but possible. The exam may mention ES256 as a target for confusion.
To protect against kid injection, validate the `kid` value against a whitelist of allowed key identifiers. Do not use `kid` directly in file paths or database queries without sanitization. If possible, avoid using `kid` entirely and use a fixed key or JWKS URI. On the exam, you may be asked to identify that `kid` injection can lead to path traversal or SQLi.
Common tools include `jwt-cracker` (a simple Node.js tool), `hashcat` with mode 16500, and `jwt_tool` with the `-C` flag. For example: `jwt_tool <token> -C -d /usr/share/wordlists/rockyou.txt`. `hashcat` can be faster for large wordlists. On the exam, you may need to know the command syntax or identify that a weak secret can be cracked.
Storing JWT in local storage is risky because it is accessible to JavaScript, making it vulnerable to XSS attacks. If an attacker injects malicious script, they can steal the token. A more secure approach is to store the token in an HTTP-only cookie, which is not accessible to JavaScript. However, this may require additional CSRF protections. On the exam, know that local storage is not secure against XSS.
The `jku` (JWK Set URL) header points to a URL from which the server can fetch the public key set. An attacker can exploit this by changing `jku` to point to an attacker-controlled URL that returns a forged public key. The attacker then signs a token with the corresponding private key. The server, trusting the `jku`, will use the attacker's public key to verify the token. This is a form of key injection.
You've just covered JWT Token Attacks — now see how well it sticks with free PT0-002 practice questions. Full explanations included, no account needed.
Done with this chapter?