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

# JWT - multiple vulnerabilities

### JWT

A JWT (JSON Web Token) is a signed token a server issues after login. It has three parts: header, payload, and signature. The payload carries claims such as `user: willem` or `role: admin`. The attack starts when the application trusts those claims too much. If you can change the payload and still make the token verify, you can impersonate other users or escalate privileges. Most vulnerable implementations fail during signature verification. Common mistakes include accepting `alg: none`, switching from `RS256` to `HS256` and using the public key as the HMAC secret, or relying on a weak HMAC secret that can be brute-forced offline. The impact is usually full account takeover or admin access. A forged token becomes a forged identity. Fix this by pinning a strong algorithm, rejecting `none`, using long random secrets or proper asymmetric key handling, and only trusting claims that are cryptographically verified.

***

### JWT: JWK header injection (Auth bypass)

**REQUIREMENTS:**

* A JWT must be used for authentication and the server must accept JWK headers for key discovery without proper validation.
* BURP active scanner message : JWT self-signed JWK header supported

**REFERENCE:**

* <https://www.youtube.com/watch?v=Y94VBDvUxlc&#x20>;
* <https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jwk-header-injection>

**DESCRIPTION:**

after the attacker captures a valid JWT, they can modify the JWK header to point to a malicious key they control. The server will then use this key to verify the signature of the JWT, allowing the attacker to bypass authentication and potentially gain unauthorized access to protected resources.

**1. Find a Vulnerable Request**

Capture a request flagged by Burp's active scanner as "JWT self-signed JWK header supported, and send it to Repeater.

**2. Generate a New RSA Key (JWT Editor Plugin)**

* Open the JWT Editor plugin and click "New RSA Key" (RS256)
* Set the parameters:
  * Format: JWK
  * Key size: 2048
  * ID: (leave empty)
* Click "Generate", then "OK".

**3. Modify the JWT Payload**

In Repeater, open the "JSON Web Token" subtab and update the "sub" claim

```json
{
    "iss": "portswigger",
    "exp": 1778426708,
    "sub": "administrator"
}
```

**4. Sign with the Embedded JWK Attack**

Click "Attack" (bottom left) > "Embedded JWK", then:

* Select the RSA key generated in step 2
* Confirm the algorithm is RS256
* Click "OK"

**5. Access the Admin Panel**

Your JWT is now forged and signed. Send the request - you should now have access to /admin

### JWT: bypass via kid header path traversal (Auth bypass)

**REQUIREMENTS:**

* Burp Suite with the **JWT Editor** extension installed
* A target application that uses JWTs and references keys via the `kid` header
* BURP active scanner message : N/A

**REFERENCE:**

* <https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-kid-header-path-traversal&#x20>;
* <https://youtu.be/YQhr82GXk8o>

**DESCRIPTION:**

This walkthrough demonstrates exploiting a JWT vulnerability where the `kid` (Key ID) header parameter is used to load a signing key from the filesystem without proper sanitization. By pointing `kid` to a predictable file containing known contents (such as `/dev/null`, which is empty), an attacker can forge a valid signature.

**1. Capture a valid JWT**&#x20;

Log in to the application through Burp's proxy and capture the response containing your session JWT. Send the authenticated request to **Repeater**.

**2. Open the JSON Web Token tab**&#x20;

In Repeater, navigate to the **JSON Web Token** sub-tab to view the decoded JWT structure.

**3. Modify the header and payload**&#x20;

Update the `kid` parameter to traverse the filesystem and point to `/dev/null` (an empty file), then escalate the `sub` claim to an administrative user:

```json
// Header
{
  "kid": "../../../../../../../../dev/null",
  "alg": "HS256"
}
 
// Payload
{
  "iss": "portswigger",
  "exp": 1778851287,
  "sub": "administrator"
}
```

**4. Generate a symmetric key**&#x20;

Open the **JWT Editor** tab and click **New Symmetric Key**. Accept the auto-generated key and click **OK**.

**5. Override the key value with a null byte**&#x20;

Double-click the newly created key and replace the `k` value with `AA==` - the Base64 encoding of a single null byte. This matches what the server will read from `/dev/null`:

```json
{
  "kty": "oct",
  "kid": "ee713f27-4e41-406f-9667-388102524f40",
  "k": "AA=="
}
```

Click **OK** to save.

**6. Sign the forged token**&#x20;

Return to Repeater's **JSON Web Token** tab and click **Sign** at the bottom of the editor. Select the symmetric key created in the previous step, ensure **Don't modify header** is selected, and confirm with **OK**.

**7. Deliver the payload**&#x20;

Send the request to an authenticated administrative endpoint (e.g., `/admin`). Because the server resolves `kid` to `/dev/null` and uses its empty contents as the HMAC secret - which matches our null-byte key - the signature validates and the forged `administrator` claim is accepted.

### JWT: bypass via JKU header injection (Auth bypass)

**REQUIREMENTS:**

* Burp Suite with the **JWT Editor** extension installed
* A target application that supports JKU headers within the JWT
* BURP active scanner message : JWT arbitrary jku header supported

**REFERENCE:**

* <https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jku-header-injection&#x20>;
* <https://youtu.be/nKspdXGrZhI>

**DESCRIPTION:**

Forge a JWT as `administrator` by abusing the `jku` (JWK Set URL) header. The server trusts the URL in `jku` to fetch the public key used for verification. If we point it at our own server, we sign with our own key and the server verifies it as valid.

**1. Capture a valid JWT**

Log in to the application as a normal user and grab the JWT issued at login. Send the authenticated request (e.g. `GET /my-account`) to Burp Repeater.

**2. Generate an attacker RSA key**

In JWT editor, generate a new RSA key (2048-bit). Burp will create a key pair. Copy the PUBLIC key in JWK format:

```json
{
  "kty": "RSA",
  "e": "AQAB",
  "kid": "8b6b4321-0da8-4773-bde8-e2f50e67d7c3",
  "n": "1ZZt53dGx6bLlW8m...KpKEQ"
}
```

Note the `kid` - you need it in step 4.

**3. Host the public key on the exploit server**

On the exploit server, create a new file (e.g. `/exploit`) and paste the JWK wrapped in a `keys` array (this is the JWK Set format the server expects):

```json
{
  "keys": [
    {
      "kty": "RSA",
      "e": "AQAB",
      "kid": "8b6b4321-0da8-4773-bde8-e2f50e67d7c3",
      "n": "1ZZt53dGx6bLlW8m...KpKEQ"
    }
  ]
}
```

store the file. The full URL is now something like: `https://exploit-<id>.exploit-server.net/exploit`

**4. Modify the JWT header**

Back in Repeater > `JSON Web Token` tab, edit the JWT header so that:

* `jku` points to your hosted JWK Set
* `kid` matches the `kid` of the public key you just hosted
* `alg` stays `RS256`

```json
{
  "kid": "8b6b4321-0da8-4773-bde8-e2f50e67d7c3",
  "alg": "RS256",
  "jku": "https://exploit-<id>.exploit-server.net/exploit"
}
```

**5. Modify the payload**

Change `sub` to `administrator`:

```json
{
  "iss": "portswigger",
  "exp": 1778855709,
  "sub": "administrator"
}
```

**6. Sign and send**

Go to Repeater tab > JSON web token > `Sign` > select the RSA key from step 2 > `Don't modify header` (so `jku`/`kid` stay intact) > click on OK. Change the request target to `/admin` (or `/admin/delete?username=carlos`) and send.

The server fetches your JWK Set via `jku`, finds the key matching `kid`, verifies the signature successfully, and treats the request as administrator.
