Skip to content

ItsWanheda/jwt-analyzer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ” JWT Analyzer

A CLI security tool for analyzing, testing, and breaking JSON Web Tokens. Built for pentesters, bug bounty hunters, and security teams who need to actually understand what's inside a JWT, not just decode it.

Python 3.9+ License: MIT Version Docker


⚑ Quick Start

# Option 1: pip (fastest for daily use)
pip install jwt-analyzer
jwt-analyzer audit --token-file token.txt

# Option 2: from source
git clone https://github.com/yourusername/jwt-analyzer.git
cd jwt-analyzer
pip install -r requirements.txt
python main.py audit --token-file sample_token.txt

# Option 3: Docker (best for CI/CD)
docker compose --profile audit run --rm jwt-analyzer \
    audit --token-file /tokens/jwt.txt

The audit command is the main one β€” it runs every check and gives you a report.


πŸ€” What does it actually do?

Most JWT tools just decode the base64. This one actually looks for problems:

Check What it finds
none algorithm detection Servers that accept unsigned tokens (CVE-2015-9235)
Algorithm confusion RS256 tokens that could be forged as HS256
kid header injection SQLi / path traversal / command injection via the kid claim
PII / secret scanning Credit cards, SSNs, AWS keys, passwords leaking through payloads
Brute-force attack Cracks HS256 secrets using wordlists (multi-threaded)
JWKS verification Validates tokens against live identity providers
Payload diffing Shows exactly what changed between two tokens
Token forgery Crafts new tokens with custom payloads (for auth testing)

πŸ“¦ Installation

From source (recommended for development)

git clone https://github.com/yourusername/jwt-analyzer.git
cd jwt-analyzer
pip install -r requirements.txt

Runtime requirements (requirements.txt):

  • Python 3.9+
  • pyjwt[crypto] >= 2.8.0 β€” RS/ES algorithm support
  • cryptography >= 41.0.0 β€” crypto backend
  • requests >= 2.31.0 β€” JWKS fetching
  • rich >= 13.0.0 β€” pretty terminal output
  • click >= 8.1.0 β€” CLI framework
  • pyyaml >= 6.0 β€” config file support

Dev requirements (requirements-dev.txt):

  • pytest >= 7.0
  • pytest-cov >= 4.0
  • mypy >= 1.0
  • ruff >= 0.1.0 (linter)

Via Docker

docker pull yourusername/jwt-analyzer:latest
# or build locally:
docker compose build

Via pip (when published to PyPI)

pip install jwt-analyzer

πŸ’» System Requirements

Component Minimum Tested
Python 3.9 3.14.6
RAM 256 MB 1 GB (large wordlists)
Disk 50 MB 200 MB (with bundled wordlists)
OS Any Windows 10/11 / Ubuntu 22.04 / macOS 14

Windows users: Use py instead of python to launch scripts. Token files saved by PowerShell Set-Content may carry a UTF-8 BOM β€” the tool strips it automatically (utf-8-sig encoding), so this is transparent.

Python version notes

  • 3.9 – 3.13: Fully supported.
  • 3.14: Fully supported. Note that 3.14's re module enforces stricter pattern parsing, which surfaced one IPv4 regex bug in v1.2.0 (fixed in v1.2.1).

πŸš€ Usage

Main command: audit

Runs every check and produces a report. This is what you want 90% of the time.

python main.py audit --token-file tokens/jwt.txt

Output:

Audit Summary
  Critical: 2
  High:     1
  Medium:   0
  Low:      0

❌ Critical findings - exiting with code 2

Save reports:

# JSON only (machine-readable, good for piping)
python main.py audit --token-file token.txt \
    --output reports/audit-1 --format json

# HTML only (great for sharing with non-tech stakeholders)
python main.py audit --token-file token.txt \
    --output reports/audit-1 --format html

# Both
python main.py audit --token-file token.txt \
    --output reports/audit-1 --format both

Useful flags:

# Skip brute force if you've already tested that vector
python main.py audit --token-file token.txt --skip-bruteforce

# Use a bigger wordlist + more workers
python main.py audit --token-file token.txt \
    --wordlist /usr/share/wordlists/jwt-secrets-10k.txt \
    --workers 16

# Enable verbose/debug logging
python main.py --verbose audit --token-file token.txt

Individual commands

Sometimes you want just one thing. These are the building blocks:

analyze β€” decode and inspect

python main.py analyze --token-file token.txt

Shows header, payload, and expiry status. No signature verification.

security β€” vulnerability checks only

python main.py security --token-file token.txt

Checks for none alg, algorithm confusion, and kid injection.

brute-force β€” crack the signing secret

python main.py brute-force --token-file token.txt \
    --wordlist utils/wordlists/common_secrets.txt \
    --workers 8

Tries every secret in the wordlist. Parallel by default. Only tests symmetric algorithms (HS256/384/512) β€” asymmetric ones use keys, not secrets.

diff β€” compare two tokens

python main.py diff --token1 old.txt --token2 new.txt

Perfect for "I had role: user and now I want role: admin, what changed?"

verify-rsa β€” verify with a public key

# PEM format
python main.py verify-rsa --token-file token.txt --public-key public.pem

# JWK format (auto-detected)
python main.py verify-rsa --token-file token.txt --public-key key.jwk

verify-jwks β€” verify against a live JWKS endpoint

python main.py verify-jwks --token-file token.txt \
    --jwks-url https://auth.example.com/.well-known/jwks.json

# Skip TLS verification (debug only)
python main.py verify-jwks --token-file token.txt \
    --jwks-url https://localhost:8443/jwks \
    --no-verify-ssl

forge β€” create a custom token

python main.py forge \
    --token-file original.txt \
    --payload-file new-payload.json \
    --secret mysecret \
    --algorithm HS256 \
    --output forged.txt \
    --yes

⚠️ See Security & Ethics before using this. The --yes flag exists because we want you to think twice.


πŸ“‚ Project Structure

jwt-analyzer/
β”œβ”€β”€ main.py                       # CLI entry point
β”œβ”€β”€ config.py                     # Configuration & env vars
β”œβ”€β”€ Dockerfile                    # Production container
β”œβ”€β”€ Dockerfile.dev                # Dev container with live reload
β”œβ”€β”€ docker-compose.yml            # Multi-profile orchestration
β”œβ”€β”€ Makefile                      # Convenience commands
β”œβ”€β”€ requirements.txt              # Runtime dependencies
β”œβ”€β”€ requirements-dev.txt          # Test/dev dependencies
β”œβ”€β”€ .env.example                  # Documented env vars
β”‚
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ parser.py                 # JWT parsing & claim extraction
β”‚   β”œβ”€β”€ security.py               # Vuln checks (none alg, kid injection, etc.)
β”‚   β”œβ”€β”€ verification.py           # RSA/ECDSA public key verification
β”‚   β”œβ”€β”€ forgery.py                # Token crafting
β”‚   β”œβ”€β”€ diff.py                   # Payload comparison
β”‚   β”œβ”€β”€ jwks.py                   # JWKS endpoint fetching + caching
β”‚   β”œβ”€β”€ sensitive_scanner.py      # PII / secret detection
β”‚   β”œβ”€β”€ async_security.py         # Parallel brute force
β”‚   └── logging_config.py         # JSON + console logging
β”‚
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ io.py                     # File reading helpers
β”‚   β”œβ”€β”€ report.py                 # HTML report generation
β”‚   └── wordlists/
β”‚       └── common_secrets.txt    # Bundled wordlist (~10k secrets)
β”‚
β”œβ”€β”€ plugins/                      # Custom check plugins (optional)
β”‚   └── README.md                 # How to write plugins
β”‚
β”œβ”€β”€ scripts/
β”‚   └── batch_audit.sh            # Process a directory of tokens
β”‚
β”œβ”€β”€ sample_token.txt              # Try it immediately
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md                     # You are here
β”œβ”€β”€ CHANGELOG.md
β”œβ”€β”€ CONTRIBUTING.md
└── SECURITY.md

βš™οΈ Configuration

Environment variables

All have sensible defaults. Override when needed:

Variable Default Description
JWTANALYZER_WORDLIST_PATH utils/wordlists/common_secrets.txt Path to secrets wordlist
JWT_ANALYZER_TIMEOUT 300 Brute force timeout (seconds)
JWT_ANALYZER_WORKERS 8 Parallel workers for brute force
JWT_ANALYZER_LOG_LEVEL INFO DEBUG / INFO / WARNING / ERROR
JWT_ANALYZER_ENABLE_RICH true Pretty terminal output

Example:

JWT_ANALYZER_LOG_LEVEL=DEBUG \
JWT_ANALYZER_WORKERS=16 \
python main.py audit --token-file token.txt

Or use the .env.example template:

cp .env.example .env
# edit .env
set -a && source .env && set +a
python main.py audit --token-file token.txt

Config file (optional)

Drop a jwt-analyzer.yaml in your working directory to override defaults without env vars:

wordlist_path: /opt/secrets/jwt-megalist.txt
brute_force_timeout: 600
parallel_workers: 16
log_level: DEBUG

🐳 Docker Usage

Available profiles

The docker-compose.yml uses profiles so nothing auto-starts. Pick the one that matches your workflow:

Profile Use case
audit One-off analysis of a single token
ci Automated scans in CI/CD pipelines (respects exit codes)
dev Live development with source mounted as volume
batch Process a directory of tokens overnight
jwks Fetch and inspect JWKS endpoint contents

Quick examples

Audit a single token:

docker compose --profile audit run --rm jwt-analyzer \
    audit --token-file /tokens/jwt.txt \
          --output /reports/audit-1

Verify against a live JWKS:

docker compose --profile jwks run --rm jwt-analyzer \
    verify-jwks --token-file /tokens/jwt.txt \
                --jwks-url https://auth.example.com/.well-known/jwks.json

Batch process a directory:

# Drop JWTs (one per .txt file) into ./tokens/batch/, then:
docker compose --profile batch up
ls reports/batch/

CI/CD integration

Exit codes for pipeline gating:

  • 0 = clean (only LOW/MEDIUM findings, or none)
  • 1 = HIGH severity findings
  • 2 = CRITICAL findings

GitHub Actions example:

- name: JWT Security Audit
  run: |
    docker compose --profile ci run --rm \
      -v ${{ github.workspace }}/tokens:/app/tokens:ro \
      jwt-analyzer audit \
        --token-file /app/tokens/prod-jwt.txt \
        --skip-bruteforce

GitLab CI example:

jwt-audit:
  stage: security
  script:
    - docker compose --profile ci run --rm
        -v "$CI_PROJECT_DIR/tokens:/app/tokens:ro"
        jwt-analyzer audit
          --token-file /app/tokens/jwt.txt
          --skip-bruteforce
  allow_failure: false

Development mode

Live-reload your source code changes without rebuilding the image:

docker compose --profile dev run --rm -it jwt-analyzer bash
# Now you're inside the container:
python main.py audit --token-file /tokens/jwt.txt

πŸ” Example Workflow

A realistic pentest scenario:

# 1. Found a JWT in the app's localStorage. Dump it.
python main.py analyze --token-file captured.txt

# 2. Quick security check - 'none' alg? weak kid? confused algorithms?
python main.py security --token-file captured.txt

# 3. Try to crack the signing secret
python main.py brute-force --token-file captured.txt \
    --wordlist utils/wordlists/common_secrets.txt

# 4. Got the secret. Compare a normal user token vs admin token
python main.py diff --token1 user-token.txt --token2 admin-token.txt
# β†’ role changed from "user" to "admin", exp extended

# 5. Forge a new admin token
cat > admin-payload.json << EOF
{
  "sub": "1234567890",
  "role": "admin",
  "exp": 9999999999
}
EOF

python main.py forge \
    --token-file captured.txt \
    --payload-file admin-payload.json \
    --secret cracked-secret \
    --output forged-admin.txt \
    --yes

# 6. Full audit with report for the writeup
python main.py audit --token-file captured.txt \
    --output reports/final-audit \
    --format both

🧩 Plugins

Custom checks can be added without modifying core code. Drop a file in plugins/ that exposes a register() function:

# plugins/my_checks_plugin.py
class MyOrgClaimsPlugin:
    name = "myorg_claims"
    description = "Validates organization-specific JWT claims"

    def check(self, token: str) -> dict:
        # your custom check logic
        ...

def register():
    return MyOrgClaimsPlugin()

Plugins auto-load on startup. See plugins/README.md for the full API.


πŸ”§ Troubleshooting

'utf-8' codec can't decode byte 0xb1

Your token file was saved with a non-UTF-8 encoding (usually a UTF-8 BOM from Windows PowerShell). Re-save it:

Get-Content sample_token.txt -Encoding UTF8 | Set-Content sample_token.txt -Encoding UTF8 -NoNewline

The tool also auto-handles BOM in v1.2.1+, so this is usually a one-time fix.

No such command 'brute_force'

Click maps function names to hyphenated command names. Use the hyphenated form:

python main.py brute-force --token-file token.txt   # βœ…
python main.py brute_force --token-file token.txt   # ❌

python: command not found (Windows)

Use py instead:

py main.py audit --token-file token.txt

re.PatternError: nothing to repeat

You're on Python 3.14 with an older build. Upgrade to v1.2.1 or later β€” this was fixed in the IPv4 pattern.

Forge produces a 3-segment token but it won't verify

Check that --secret matches the original token's signing secret. Run analyze on both the original and forged tokens and compare headers β€” they should be identical except for alg.


πŸ›‘οΈ Security & Ethics

Read this. Seriously.

This tool can forge tokens, crack secrets, and bypass authentication. That's the point, but it also means you can hurt people with it.

βœ… Do

  • Only test systems you have written authorization to test
  • Use it for security audits, bug bounties, CTFs, your own apps, and education
  • Document what you found and how (that's what --output reports/ is for)
  • Follow responsible disclosure for any vulns you discover

❌ Don't

  • Don't run this against systems you don't own or have explicit permission for
  • Don't use it to access accounts that aren't yours
  • Don't be the reason computer fraud laws exist

Unauthorized access to computer systems is illegal in most jurisdictions (CFAA in the US, Computer Misuse Act in the UK, similar laws everywhere). The --yes flag on forge exists because we want you to think twice.

Reporting vulnerabilities in THIS tool

Found a security bug in jwt-analyzer itself? Please email [email protected] (do not open a public GitHub issue). See SECURITY.md for our full disclosure policy.


🀝 Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.

Quick checklist for PRs:

  • New functionality is documented in the README
  • Entry added to CHANGELOG.md under [Unreleased]
  • No new hardcoded paths or secrets
  • Code passes ruff check and mypy if you ran them locally
  • Plugin additions follow the pattern in plugins/README.md

πŸ“ License

MIT β€” see LICENSE for the full text.

In short: do what you want, just don't blame us if something goes wrong, and keep the copyright notice.


πŸ™ Credits

  • The OWASP JWT cheat sheet β€” for the vulnerability patterns
  • SecLists β€” bundled wordlists
  • The PyJWT maintainers β€” solid crypto library
  • Everyone who's reported bugs and contributed fixes

πŸ“š Further reading