Scripting & Automation
JWT-HACK is designed to work well in scripts and automated workflows. Use the
global --json flag to get machine-readable output for any command.
Exit Codes and Result Detection
Important: JWT-HACK does not signal outcomes like "signature invalid" or "secret not found" through exit codes. Commands such as
decode,verify, andcrackstill exit0in those cases. The result is reported in the output, not the status code. Do not branch onjwt-hack verify ...succeeding/failing.
Observed exit codes:
- 0 - The command ran (this includes "token invalid" and "secret not found")
- 1 - A hard error while producing
--jsonoutput, or a config/runtime failure - 2 - Invalid command-line arguments (from argument parsing)
To detect results reliably, use --json and inspect the response fields:
# verify → parse the "valid" boolean
jwt-hack --json verify "$TOKEN" --secret="$SECRET" | jq -e '.valid == true'
# crack → "found" is true and "value" holds the secret
jwt-hack --json crack -w wordlist.txt "$TOKEN" | jq -e '.found == true'
Bash Scripting
Basic Token Validation
#!/bin/bash
validate_token() {
local token="$1"
local secret="$2"
# verify exits 0 even for an invalid signature, so check the JSON "valid" field.
if [ "$(jwt-hack --json verify "$token" --secret="$secret" | jq -r '.valid')" = "true" ]; then
echo "Token is valid"
return 0
else
echo "Token is invalid"
return 1
fi
}
# Usage
if validate_token "$JWT_TOKEN" "$SECRET"; then
echo "Proceeding with authenticated request"
else
echo "Authentication failed"
exit 1
fi
Batch Token Processing
#!/bin/bash
# Process multiple tokens from file
while IFS= read -r token; do
echo "Processing token: ${token:0:20}..."
if jwt-hack decode "$token" > /dev/null 2>&1; then
echo "✓ Valid format"
jwt-hack decode "$token" | grep -E "(exp|iat)"
else
echo "✗ Invalid format"
fi
echo "---"
done < tokens.txt
Automated Cracking
#!/bin/bash
crack_token() {
local token="$1"
local wordlist="$2"
echo "Attempting to crack token..."
# crack exits 0 whether or not a secret is found, so check the JSON output.
local json secret
json=$(jwt-hack --json crack -w "$wordlist" "$token")
if [ "$(echo "$json" | jq -r '.found')" = "true" ]; then
secret=$(echo "$json" | jq -r '.value')
echo "SUCCESS: Secret found: $secret"
return 0
else
echo "FAILED: Could not crack token"
return 1
fi
}
# Try multiple wordlists
wordlists=("/usr/share/wordlists/rockyou.txt" "custom.txt" "common.txt")
for wordlist in "${wordlists[@]}"; do
if [[ -f "$wordlist" ]]; then
echo "Trying wordlist: $wordlist"
if crack_token "$JWT_TOKEN" "$wordlist"; then
break
fi
fi
done
Python Integration
Using subprocess
import subprocess
import json
import sys
def decode_jwt(token):
"""Decode a JWT and return the parsed JSON result, or None on error."""
result = subprocess.run(
['jwt-hack', '--json', 'decode', token],
capture_output=True, text=True
)
data = json.loads(result.stdout or '{}')
return data if data.get('success') else None
def verify_jwt(token, secret):
"""Verify a JWT signature. Returns True only if the JSON `valid` field is true."""
result = subprocess.run(
['jwt-hack', '--json', 'verify', token, '--secret', secret],
capture_output=True, text=True
)
data = json.loads(result.stdout or '{}')
return bool(data.get('valid'))
# Usage
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
if decode_result := decode_jwt(token):
print("Token decoded successfully")
print(decode_result)
else:
print("Failed to decode token")
sys.exit(1)
Note: jwt-hack does not use exit codes to report an invalid signature or a failed crack. Always pass
--jsonand inspect the response fields (valid,found,value, …) rather than relying oncheck=True.
Token Analysis Pipeline
#!/usr/bin/env python3
import subprocess
import json
import re
from pathlib import Path
class JWTAnalyzer:
def __init__(self):
self.jwt_hack = "jwt-hack"
def _run_json(self, *args):
"""Run a jwt-hack subcommand with --json and return the parsed result."""
result = subprocess.run(
[self.jwt_hack, '--json', *args],
capture_output=True, text=True
)
return json.loads(result.stdout or '{}')
def decode(self, token):
"""Decode JWT and return the structured JSON result."""
data = self._run_json('decode', token)
return data if data.get('success') else None
def verify(self, token, secret):
"""Verify JWT signature via the JSON `valid` field."""
data = self._run_json('verify', token, '--secret', secret)
return bool(data.get('valid'))
def crack(self, token, wordlist):
"""Attempt to crack the JWT secret; returns the secret or None."""
data = self._run_json('crack', '-w', wordlist, token)
return data.get('value') if data.get('found') else None
def generate_payloads(self, token, target='all'):
"""Generate attack payloads (returns the JSON payload list)."""
return self._run_json('payload', token, '--target', target)
# Usage example
analyzer = JWTAnalyzer()
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Analyze token
info = analyzer.decode(token)
if info:
print("Token analysis:", info)
# Try to crack it
secret = analyzer.crack(token, "wordlist.txt")
if secret:
print(f"Secret found: {secret}")
# Verify with found secret
if analyzer.verify(token, secret):
print("Secret verified!")
CI/CD Integration
GitHub Actions
name: JWT Security Check
on: [push, pull_request]
jobs:
jwt-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install JWT-HACK
run: |
cargo install jwt-hack
- name: Analyze JWT tokens in code
run: |
# Find JWT tokens in code (simple regex)
grep -r "eyJ[A-Za-z0-9_-]*\." . || true
- name: Test JWT security
run: |
# Test any hardcoded tokens
if [ -f "test-tokens.txt" ]; then
while read token; do
echo "Testing token: $token"
jwt-hack decode "$token"
jwt-hack crack -w common-passwords.txt "$token" || true
done < test-tokens.txt
fi
Docker Integration
FROM rust:1.87 as builder
RUN cargo install jwt-hack
FROM debian:bookworm-slim
COPY --from=builder /usr/local/cargo/bin/jwt-hack /usr/local/bin/
COPY scripts/ /scripts/
ENTRYPOINT ["/scripts/analyze.sh"]
Configuration Management
Environment-Based Configuration
jwt-hack itself does not read these values from the environment, so read them into shell variables and pass them explicitly as flags:
#!/bin/bash
# Set defaults from environment (your own variables, not read by jwt-hack)
SECRET="${SECRET:-default-secret}"
WORDLIST="${WORDLIST:-/usr/share/wordlists/rockyou.txt}"
CONCURRENCY="${CONCURRENCY:-$(nproc)}"
# Pass them explicitly on the command line
jwt-hack verify "$token" --secret="$SECRET"
jwt-hack crack -w "$WORDLIST" -c "$CONCURRENCY" "$token"
Config File Generation
#!/bin/bash
# Generate jwt-hack config
mkdir -p ~/.config/jwt-hack
cat > ~/.config/jwt-hack/config.toml << EOF
default_secret = "${DEFAULT_SECRET}"
default_algorithm = "${DEFAULT_ALGORITHM:-HS256}"
default_wordlist = "${DEFAULT_WORDLIST}"
default_private_key = "${DEFAULT_PRIVATE_KEY}"
EOF
echo "Configuration generated at ~/.config/jwt-hack/config.toml"