# 6.3 JWT Attacks

{% embed url="<http://portswigger.net/web-security/jwt>" %}

## What are JWTs? <a href="#what-are-jwts" id="what-are-jwts"></a>

JSON web tokens (JWTs) are a standardized format for sending cryptographically signed JSON data between systems. They can contain any kind of data, but are most commonly used to claim/send info about users as a part of authentication, session handling and access control mechanisms.

In this case, all data that a server needs is stored client-side within the JWT, so it is a good way that permits to interact users with multiple back-end servers (that's the standard situation in the modern system architectures).

### JWT format

A JWT consists of 3 parts: a header, a payload, and a signature, each separated by a dot.

* Header: base64url-encoded, contains metadata about the token;
* Payload: base64url-encoded, contains the actual "claims" about the user (decoding it we can see more interesting data: name, email, etc);
* Signature: it usually generated from the server that issues the token throught the hashing of the header and payload.

To analyze well the structure of JWTs we can use the debugger on `jwt.io`.

### JWT vs JWS vs JWE <a href="#jwt-vs-jws-vs-jwe" id="jwt-vs-jws-vs-jwe"></a>

<figure><img src="/files/zRLUIIbif2JvhMA5wGT3" alt=""><figcaption><p><a href="https://portswigger.net/web-security/jwt/images/jwt-jws-jwe.jpg">https://portswigger.net/web-security/jwt/images/jwt-jws-jwe.jpg</a></p></figcaption></figure>

The JWT defines a format for representing information ("claims") as a JSON object that can be transferred between two parties. It's really used as a standalone entity and is more frequently extended by: JSON Web Signature (JWS) and JSON Web Encryption (JWE) specifications.

So, JWT is usually either a JWS or JWE token (90% JWS). In JWS token the data are encoded, while into JWE are encrypted.

According to the JWS specification, only the `alg` header parameter is mandatory. In practice, however, JWT headers (also known as JOSE headers) often contain several other parameters. The following ones are of particular interest to attackers.

* `jwk` (JSON Web Key) - Provides an embedded JSON object representing the key.
* `jku` (JSON Web Key Set URL) - Provides a URL from which servers can fetch a set of keys containing the correct key.
* `kid` (Key ID) - Provides an ID that servers can use to identify the correct key in cases where there are multiple keys to choose from. Depending on the format of the key, this may have a matching `kid` parameter.

## JWT Attacks

### Injecting self-signed JWTs via the jwk parameter <a href="#injecting-self-signed-jwts-via-the-jwk-parameter" id="injecting-self-signed-jwts-via-the-jwk-parameter"></a>

The JSON Web Signature (JWS) specification describes an optional `jwk` header parameter, which servers can use to embed their public key directly within the token itself in JWK format (it rapresents keys as a JSON object). Here below an example of JWT Header:

```json
{
    "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
    "typ": "JWT",
    "alg": "RS256",
    "jwk": {
        "kty": "RSA",
        "e": "AQAB",
        "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
        "n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
    }
}
```

Misconfigured servers sometimes use any key that's embedded in the `jwk` parameter.

You can exploit this behavior by signing a modified JWT using your own RSA private key, then embedding the matching public key in the `jwk` header.

You can also perform this attack manually by adding the `jwk` header yourself. However, you may also need to update the JWT's `kid` header parameter to match the `kid` of the embedded key.

1. With the extension loaded, in Burp's main tab bar, go to the **JWT Editor Keys** tab.
2. [Generate a new RSA key.](https://portswigger.net/burp/documentation/desktop/testing-workflow/session-management/jwts#adding-a-jwt-signing-key)
3. Send a request containing a JWT to Burp Repeater.
4. In the message editor, switch to the extension-generated **JSON Web Token** tab and [modify](https://portswigger.net/burp/documentation/desktop/testing-workflow/session-management/jwts#editing-jwts) the token's payload however you like.
5. Click **Attack**, then select **Embedded JWK**. When prompted, select your newly generated RSA key.
6. Send the request to test how the server responds.

### Injecting self-signed JWTs via the jku parameter

Instead of embedding public keys directly using the `jwk` header parameter, some servers let you use the `jku` (JWK Set URL) header parameter to reference a JWK Set containing the key. When verifying the signature, the server fetches the relevant key from this URL\
A JWK Set is a JSON object containing an array of JWKs representing different keys. You can see an example of this below.

```json
{
    "keys": [
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
            "n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
        },
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
            "n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
        }
    ]
}
```

JWK Sets like this are sometimes exposed publicly via a standard endpoint, such as `/.well-known/jwks.json`.

### Injecting self-signed JWTs via the kid parameter <a href="#injecting-self-signed-jwts-via-the-kid-parameter" id="injecting-self-signed-jwts-via-the-kid-parameter"></a>

Servers may use several cryptographic keys for signing different kinds of data, not just JWTs. For this reason, the header of a JWT may contain a `kid` (Key ID) parameter, which helps the server identify which key to use when verifying the signature.

Verification keys are often stored as a JWK Set.

However, the JWS specification doesn't define a concrete structure for this ID - it's just an arbitrary string of the developer's choosing. For example, they might use the `kid` parameter to point to a particular entry in a database, or even the name of a file.

If this parameter is also vulnerable to directory traversal, an attacker could potentially force the server to use an arbitrary file from its filesystem as the verification key.

```json
{
    "kid": "../../path/to/file",
    "typ": "JWT",
    "alg": "HS256",
    "k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc"
}
```

This is especially dangerous if the server also supports JWTs signed using a [symmetric algorithm](https://portswigger.net/web-security/jwt/algorithm-confusion#symmetric-vs-asymmetric-algorithms). In this case, an attacker could potentially point the `kid` parameter to a predictable, static file, then sign the JWT using a secret that matches the contents of this file.

You could theoretically do this with any file, but one of the simplest methods is to use `/dev/null`, which is present on most Linux systems. As this is an empty file, reading it returns an empty string. Therefore, signing the token with a empty string will result in a valid signature.

Note: If you're using the JWT Editor extension, note that this doesn't let you sign tokens using an empty string. However, due to a bug in the extension, you can get around this by using a Base64-encoded null byte. If the server stores its verification keys in a database, the `kid` header parameter is also a potential vector for SQL injection attacks.

#### Other interesting JWT header parameters <a href="#other-interesting-jwt-header-parameters" id="other-interesting-jwt-header-parameters"></a>

* `cty` (Content Type) - Sometimes used to declare a media type for the content in the JWT payload.&#x20;
* `x5c` (X.509 Certificate Chain) - Sometimes used to pass the X.509 public key certificate or certificate chain of the key used to digitally sign the JWT.&#x20;

### JWT algorithm confusion <a href="#jwt-algorithm-confusion" id="jwt-algorithm-confusion"></a>

Even if a server uses robust secrets that you are unable to brute-force, you may still be able to forge valid JWTs by signing the token using an algorithm that the developers haven't anticipated. This is known as an algorithm confusion attack.

#### **An Example of Attack** <a href="#how-to-prevent-jwt-attacks" id="how-to-prevent-jwt-attacks"></a>

A JWT (JSON Web Token) can often be captured during authentication or while accessing protected endpoints. This can be done by intercepting traffic with tools like **Burp Suite**, where the token is usually found in the `Authorization` header as a **Bearer token**, or by inspecting the browser's **Developer Tools** under the **Storage** or **Network** tabs.

Once the token is captured, it can be analyzed using [JWT.io](https://jwt.io), which allows you to decode the token and inspect both the **header** and **payload**. If the JWT is using a **weak or guessable secret key**, and the algorithm is something like **HS256**, you may be able to brute-force the signature using tools like **John the Ripper** or **Hashcat**.

**Methodology**:

* Extract the token and place it in a suitable format for cracking.
* Use a popular wordlist like `rockyou.txt` to attempt to recover the secret used to sign the JWT.

If the secret is successfully recovered, you can:

* Forge your own valid tokens.
* Modify the payload (e.g., change `role: user` to `role: admin`) and re-sign it using the discovered secret.

## How to prevent JWT attacks <a href="#how-to-prevent-jwt-attacks" id="how-to-prevent-jwt-attacks"></a>

You can protect your own websites against many of the attacks we've covered by taking the following high-level measures:

* Use an up-to-date library for handling JWTs and make sure your developers fully understand how it works, along with any security implications.&#x20;
* Make sure that you perform robust signature verification on any JWTs that you receive, and account for edge-cases such as JWTs signed using unexpected algorithms.
* Enforce a strict whitelist of permitted hosts for the `jku` header.
* Make sure that you're not vulnerable to path traversal or SQL injection via the `kid` header parameter.

#### Additional best practice for JWT handling

* Always set an expiration date for any tokens that you issue.
* Avoid sending tokens in URL parameters where possible.
* Include the `aud` (audience) claim (or similar) to specify the intended recipient of the token. This prevents it from being used on different websites.
* Enable the issuing server to revoke tokens (on logout, for example).

Although not strictly necessary to avoid introducing vulnerabilities, we recommend adhering to the following best practice when using JWTs in your applications:f

## Labs 🔬

* [JWT authentication bypass via unverified signature](https://dev-angelist.gitbook.io/writeups-and-walkthroughs/portswigger-web-security-academy/jwt-attacks/exploiting-jwt/jwt-authentication-bypass-via-unverified-signature)
* [JWT authentication bypass via flawed signature verification](https://dev-angelist.gitbook.io/writeups-and-walkthroughs/portswigger-web-security-academy/jwt-attacks/exploiting-jwt/jwt-authentication-bypass-via-flawed-signature-verification)
* [JWT authentication bypass via weak signing key](https://dev-angelist.gitbook.io/writeups-and-walkthroughs/portswigger-web-security-academy/jwt-attacks/exploiting-jwt/jwt-authentication-bypass-via-weak-signing-key)


---

# Agent Instructions: 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:

```
GET https://dev-angelist.gitbook.io/ewptxv3-notes/readme/5.5-other-common-web-attacks/6.3-jwt-attacks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
