# A complete conquest of JWT attacks [2026]: alg:none, key brute force, algorithm confusion, jwk/jku/kid injection — a version faithful to the official docs

> An in-depth look at JWT (JSON Web Token) attack techniques, faithful to the PortSwigger Web Security Academy. The mechanisms of signature-verification flaws (accepting arbitrary signatures, alg:none), hashcat brute force of weak HS256 secrets, jwk/jku/kid header injection, and RS256→HS256 algorithm confusion (key confusion), plus root-cause defenses via algorithm pinning, strict signature verification, and a jku host allowlist — explained with examples limited to your own lab.

- Published: 2026-06-28
- Author: 友田 陽大
- Tags: セキュリティ, ホワイトハッカー, JWT, 脆弱性診断, Webセキュリティ
- URL: https://tomodahinata.com/en/blog/jwt-attack-techniques-alg-none-key-confusion-secret-cracking-guide
- Category: 実践Webハッキング技法
- Pillar guide: https://tomodahinata.com/en/blog/web-application-hacking-techniques-methodology-owasp-portswigger-guide

## Key points

- JWT's security fully depends on 'signature verification.' Most attacks exploit cut corners in verification: not verifying the signature, accepting alg:none, lax verification logic — rewriting the payload to impersonate others or an admin.
- A weak secret key (HS256) can be cracked with hashcat. `hashcat -m 16500 jwt.txt wordlist` for a dictionary attack. Crack the key and you can legitimately sign arbitrary tokens = complete authentication bypass. Keys must be long and random.
- Header injection: jwk (embed a public key) / jku (point to a key-set URL) / kid (point to a key file = path traversal or SQLi). The hole is a design where the server trusts the attacker's key.
- Algorithm confusion (key confusion): send a token with alg:HS256 to a server expecting RS256, and get it to sign using the public RSA key as the 'HMAC secret key.' Since the public key is obtainable by anyone, you can forge a legitimate token.
- Root-cause defense: pin the algorithm server-side (allowlist), reject none, and strictly verify the targets of jku/kid. Use a proven up-to-date library correctly, make keys long and random, and design expiry and revocation too.

---

JWT (JSON Web Token) is widely used in authentication and session management for modern SPAs and microservices. That's exactly why **getting JWT verification wrong in one place collapses authentication entirely.** As [PortSwigger](https://portswigger.net/web-security/jwt) says, "the security of any JWT-based mechanism depends heavily on the cryptographic signature," and most attacks exploit **cut corners in that signature verification.** This article explains those attack techniques faithfully to the official source.

> **An absolute premise:** all procedures only within a [legal lab](/blog/ethical-hacking-home-lab-kali-juice-shop-ctf-self-study-roadmap-guide) or an authorized scope. Forging or impersonating others' tokens is unauthorized access if done without authorization, even for verification purposes (→ [the legal guide](/blog/ethical-hacker-law-japan-unauthorized-access-act-active-cyber-defense-disclosure-guide)). The map is the [pillar](/blog/web-application-hacking-techniques-methodology-owasp-portswigger-guide). For the basics of token design including JWT, also see [the difference between ID tokens and access tokens](/blog/id-token-vs-access-token-oidc-oauth2-guide).

---

## 1. The structure of a JWT — three parts

A JWT is `header.payload.signature`, three parts base64url-encoded and dot-separated.

```text
eyJhbGciOiJIUzI1NiJ9 . eyJzdWIiOiJ3aWVuZXIifQ . <署名>
└─ header ────────┘   └─ payload ──────────┘
{"alg":"HS256"}        {"sub":"wiener","role":"user"}
```

- **header**: meta info like the signing algorithm (`alg`).
- **payload**: claims (who, permissions, expiry, etc.). **Base64 is not encryption**, so anyone can read the contents.
- **signature**: the header+payload signed with a key. **Tamper detection relies on this alone.**

In other words, **if signature verification is lax, you can rewrite the payload to `"role":"admin"` at will.**

---

## 2. Exploiting signature-verification flaws

### 2.1 Not verifying the signature / accepting an arbitrary signature

A case where the developer confuses "decode" and "verify" and **trusts the payload without verifying the signature.** It passes just by rewriting the payload.

```text
# payload の "sub":"wiener" を "sub":"administrator" に書き換えて送るだけで通る
# （Burp の JWT Editor 拡張でワンクリック改ざん→送信できる）
```

### 2.2 alg:none

The JWS spec has "no signature (`alg:none`)." If the server accepts this, you can **empty the signature and freely tamper with the payload.**

```text
# header を {"alg":"none"} にし、署名部分を空にする
eyJhbGciOiJub25lIn0 . eyJzdWIiOiJhZG1pbmlzdHJhdG9yIn0 .
                                                       └─ 署名は空
```

Even if a simple `none` is rejected, as PortSwigger notes, obfuscation like **`None`, `nOnE`, or unexpected encodings** can slip past the verification filter.

---

## 3. Brute-forcing a weak secret key (HS256)

HMAC-family (HS256) uses **"an arbitrary string" as the secret key.** If the key is weak/default, it can be cracked with [hashcat](https://hashcat.net/).

```bash
# JWTを辞書攻撃（-m 16500 が JWT モード）。割れた鍵が標準出力に出る
hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/jwt.secrets.list

# 鍵が判明したら、任意のpayloadを「正規に」署名できる = 完全な認証バイパス
# 例: {"sub":"administrator"} を割れた鍵で署名して送る
```

**Crack the key and it's over.** So the secret key must be **sufficiently long and random** (reusing weak default keys is the typical incident). For the principles of applied cryptography and key management, see the [password-hashing/cryptography/key-management guide](/blog/password-hashing-argon2-encryption-key-management-applied-cryptography-guide).

---

## 4. Header-parameter injection (jwk / jku / kid)

The JWT spec has mechanisms to specify, in the header, the key used for signature verification. **If the server trusts these without verification, you get it to verify with the attacker's key.**

| Parameter | Meaning | Attack |
|---|---|---|
| **jwk** | Embed a public key directly in the token | Sign with your own key pair and embed the public key in jwk |
| **jku** | Point to the URL of a key set (JWK Set) | Specify the attacker's server's JWK Set in the URL |
| **kid** | The ID of the key to use (often used for a file/DB reference) | Manipulate the key via path traversal (`../../dev/null`) or SQLi |

```text
# jwk 注入の例（header に自前の公開鍵を埋め、その秘密鍵で署名）
{"alg":"RS256","typ":"JWT","jwk":{"kty":"RSA","n":"<攻撃者の公開鍵>","e":"AQAB"}}

# kid をパストラバーサルに：既知内容のファイルを鍵に使わせ、署名を予測可能にする
{"alg":"HS256","kid":"../../../../../../dev/null"}
# /dev/null は空 → 鍵が空文字列になり、攻撃者が署名を作れる
```

---

## 5. Algorithm confusion (key confusion) attack — RS256 → HS256

The most cunning is **algorithm confusion / key confusion.** It succeeds when the server assumes RS256 (asymmetric: verify with the public key, sign with the private key) but **doesn't pin the alg at verification time.**

The mechanism:

1. The RS256 **public key is obtainable by anyone** (from a JWK endpoint or certificate).
2. The attacker makes a token with the `alg` **changed to HS256 (symmetric).**
3. They sign that token **using the public-key string as the "HMAC secret key."**
4. The server judges "it's HS256" and **verifies with its public key as the HMAC key** → it matches.

```text
# 概念：本来 RS256 のサーバーへ、HS256 で署名したトークンを送る
# 署名鍵 = サーバーのRSA「公開」鍵（PEM文字列そのもの）
header  = {"alg":"HS256"}
payload = {"sub":"administrator"}
signature = HMAC-SHA256(base64(header)+"."+base64(payload), <RSA公開鍵PEM>)
```

Since the public key isn't secret, **the attacker can forge a token that "looks" legitimate.** This is the terror of key confusion (can be PoC'd with Burp's JWT Editor).

---

## 6. [Defender side] Root-cause defenses

Once you understand the attack structure, the defense is clear. It follows PortSwigger's recommendations.

```ts
// ✅ 検証時にアルゴリズムを「固定」する（最重要）。none も他algも受け付けない
import { jwtVerify } from "jose";

const { payload } = await jwtVerify(token, publicKey, {
  algorithms: ["RS256"], // ← 許可リスト。これが無いと alg 混同/none を許す
  issuer: "https://auth.example",
  audience: "https://api.example",
});
```

Design principles:

- **Pin the algorithm server-side** (allowlist). Reject `alg:none` and **don't trust the token's `alg`.** This alone blocks most alg confusion and none.
- **Always verify**: don't confuse the "decode" function (`decode`) with the "verify" function (`verify`).
- **Allowlist the hosts for jku/jwk** (don't trust keys at arbitrary URLs). **Apply path-traversal/SQLi countermeasures for kid.**
- **Make the secret key long and random** (avoid weak HS256 keys). Design key rotation.
- **Use a proven, up-to-date library** per its documentation (don't roll your own). `jose` / `jsonwebtoken`, etc.
- **Expiry (exp) and revocation**: short expiry + refresh tokens + a revocation list limit the damage on leakage.
- **Storage location**: to avoid XSS theft, consider an `HttpOnly` cookie in the browser (→ [XSS defense](/blog/xss-attack-techniques-reflected-stored-dom-csp-bypass-guide)).

Robust design as an authentication platform (selecting Cognito/Auth0/Clerk/Supabase Auth, and RS256 JWKS verification) is detailed in [authentication-platform selection](/blog/auth-platform-selection-2026-cognito-auth0-clerk-supabase) and [Cognito JWT RS256 verification](/blog/aws-cognito-jwt-rs256-verification-jwks-security-guide).

---

## 7. Summary

- **JWT's security fully depends on signature verification**: cut corners (unverified, alg:none, lax verification) are the main holes.
- **Weak keys can be cracked with hashcat**: make HS256 keys long and random.
- **Header injection**: if the server trusts jwk/jku/kid without verification, it passes with the attacker's key.
- **Algorithm confusion**: with the alg unpinned, the public key gets used as the HMAC key and tokens are forged.
- **Root-cause defense**: algorithm pinning + always verify + strict jku/kid + long keys + up-to-date library + exp/revocation.

Next, head to [the complete conquest of authentication vulnerabilities](/blog/authentication-vulnerabilities-brute-force-2fa-bypass-attack-guide), which targets the login mechanism itself.

---

### References (official primary sources)

- [PortSwigger: JWT attacks](https://portswigger.net/web-security/jwt) / [Algorithm confusion](https://portswigger.net/web-security/jwt/algorithm-confusion)
- [OWASP: JSON Web Token for Java Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html) / [RFC 8725: JWT Best Current Practices](https://www.rfc-editor.org/rfc/rfc8725)
- [hashcat official](https://hashcat.net/) / [jose (JWT library)](https://github.com/panva/jose)
