> For the complete documentation index, see [llms.txt](https://intrusionz3r0.gitbook.io/intrusionz3r0/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://intrusionz3r0.gitbook.io/intrusionz3r0/hacking-web/vulnerabilities/jwt-vulnerabilities.md).

# JWT vulnerabilities

A JWT (JSON Web Token) is like an access pass that the server gives you after you log in. It’s a long string with three parts, separated by dots:

```http
HEADER.PAYLOAD.SIGNATURE
eyJhbGciOi... (header).eyJzdWIiOi... (payload).SGVsbG8sIHdv... (signature)
```

#### What does each part contain?

1. **Header**
   * Describes the algorithm used to sign the token (e.g., HS256, RS256).
   * It's a Base64-encoded JSON.
2. **Payload**
   * Contains “claims” – data like your name, role, email, isAdmin status, etc.
   * Also a Base64-encoded JSON.
   * **Anyone can read this part if they have the token!**
3. **Signature**
   * This ensures the token hasn’t been tampered with.
   * Created using a secret key known only to the server.
   * If you change the header or payload, the signature becomes invalid.

### Risky Header Parameters

1. `alg`: Can be changed to `none` to bypass signature validation.
2. `jwk`: May allow the attacker to provide a public key and sign a token with their private key.
3. `kid`: If not validated securely, can be exploited via path traversal or external key injection.

#### **Useful resouse:**

{% embed url="<https://jwt.io/>" %}

#### Burpsuite Recommended extension:

* JWT Editor

## Methodology

### Signature Validation Bypass

* Modify the payload (e.g., change user ID, role, etc.) to impersonate another user.
* Observe if the server still accepts the token, indicating improper signature verification.

### Algorithm none Bypass

* Change the `alg` parameter in the header to `none`.
* Remove the signature part but keep the final dot (e.g., `header.payload.`).
* If accepted, the server is not validating the signature.

### Brute Force the Signature Key

* Developers may forget to change default secrets.
* Use Hashcat to brute-force the key:

```bash
hashcat -a 0 -m 16500 'HEADER.PAYLOAD.SIGNATURE' jwt.secrets.list
```

***

### Header Injection Techniques

#### 🔓 `jwk` Header Injection

* Generate an RSA key in Burp Suite.
* Modify the payload as needed.
* In Burp Repeater, use `Attack → Embedded JWK`.
* Send the token with your public key embedded in the header.

#### 🌐 `jku` Header Injection

* Host a JWK Set file like:

```json
{
  "keys": [ YOUR_JWK ]
}
```

* In the JWT header:
  * Set `kid` to your key ID.
  * Add a `jku` parameter pointing to your hosted JWK Set.
* Sign the token with your private key and send it.

#### 🗂️ `kid` Path Traversal

* Create a symmetric key in Burp.
* Replace the `k` value with a Base64-encoded null byte (`AA==`).
* In the header, set:

  ```json
  "kid": "../../../../../../../dev/null"
  ```
* Modify the payload as needed, sign and send.

***

### Algorithm Confusion Attack (RS256 → HS256)

1. Retrieve the server's public key (commonly found at `/jwks.json` or `/.well-known/jwks.json`).
2. Generate a new RSA Key in Burp → Export as PEM.
3. Convert PEM to Base64.
4. Create a Symmetric Key and replace the `k` value with the Base64 version.
5. In the header:

   ```json
   "alg": "HS256"
   ```
6. Modify the payload as needed, sign and send.

***

### Algorithm Confusion Without Exposed Key

1. Obtain two JWTs (either same user at different sessions, or different users).
2. Use `sig2n` to derive the HMAC key:

```bash
sudo docker run --rm -it portswigger/sig2n TOKEN1 TOKEN2
```

3. Copy the derived key.
4. Create a new Symmetric Key in Burp and set `k` to that key.
5. Set `alg` in the header to `HS256`.
6. Modify the payload, sign, and send.
