A powerful and flexible Burp Suite extension for detecting security issues in JWT (JSON Web Tokens). This extension acts as a Swiss Army knife for JWT security testing by allowing you to configure multiple rules to automatically create issues based on JWT claims and their values.
Created by David Robert ([email protected])
- Configurable Rules: Define multiple rules to check different JWT claims
- Flexible Matching: Support for various match types (equals, contains, startsWith, endsWith, regex)
- Custom Issues: Configure issue name, description, background, remediation, and severity for each rule
- Passive Scanning: Automatically checks JWT tokens in HTTP requests during passive scanning
- Easy Configuration: Simple JSON-based configuration file
- Built-in Rules: Ships with example rules:
- Microsoft Graph API audience detection
- Weak/no algorithm detection (none, HS256)
- Custom claim validation
The JWT Checker is a passive scanner that:
- Monitors HTTP requests for JWT tokens in the
Authorizationheader (Bearer tokens) - Decodes and analyzes the JWT (without validating the signature, validating tokens is NOT the goal of this extension)
- Applies configured rules to check various JWT claims (audience, algorithm, issuer, etc.)
- Creates Burp Suite issues when rules match, with customizable severity levels
- Provides detailed information about detected security concerns
This makes it ideal for:
- Detecting misconfigured OAuth/OIDC tokens
- Identifying weak JWT algorithms
- Finding tokens with unexpected audience, other other claims values for your organization
- Validating custom security requirements for JWT tokens
- Burp Suite (Professional Edition)
- Java 17 or higher
- Maven 3.6 or higher (for building from source)
-
Clone the repository:
git clone https://github.com/castlebbs/BurpJWTChecker.git cd BurpJWTChecker -
Build the extension using Maven:
mvn clean package
-
The compiled JAR file will be located at:
target/jwt-checker-1.0.0-jar-with-dependencies.jar
- Open Burp Suite
- Go to Extensions tab
- Click Add
- Select Extension type: Java
- Click Select file and choose the JAR file from the target directory
- Click Next
- The extension should load successfully. Check the Output tab for confirmation messages.
The extension looks for configuration files in the following order:
- User configuration:
~/.burp/jwt-checker-config.json(on Linux/Mac) orC:\Users\<username>\.burp\jwt-checker-config.json(on Windows) - Default configuration: Embedded in the JAR file (
src/main/resources/config.json)
If a user configuration file exists, it takes precedence over the default configuration.
The configuration file is a JSON file with the following structure:
{
"rules": [
{
"name": "rule-identifier",
"claimName": "claim-to-check",
"matchType": "matching-strategy",
"matchValue": "value-to-match",
"issueName": "Issue Title",
"issueDetail": "Short description",
"issueBackground": "Detailed background information",
"issueRemediation": "How to fix this issue",
"severity": "CRITICAL|HIGH|MEDIUM|LOW|INFO",
"enabled": true
}
]
}| Parameter | Description | Required | Values |
|---|---|---|---|
name |
Unique identifier for the rule | Yes | String |
claimName |
JWT claim to check (e.g., "aud", "alg", "iss", "sub") | Yes | String |
matchType |
How to match the claim value | Yes | equals, contains, startsWith, endsWith, regex |
matchValue |
Value to match against | Yes | String |
issueName |
Title of the issue in Burp Suite | Yes | String |
issueDetail |
Short summary of the issue | Yes | String |
issueBackground |
Detailed explanation of why this is an issue | Yes | String |
issueRemediation |
Recommendations for fixing the issue | Yes | String |
severity |
Issue severity level | Yes | CRITICAL, HIGH, MEDIUM, LOW, INFO |
enabled |
Whether the rule is active | Yes | true or false |
Note: Burp Suite does not have a separate "CRITICAL" severity level, so CRITICAL is mapped to HIGH severity.
alg: JWT algorithm (from header) - e.g., "RS256", "HS256", "none"aud: Audience claim - can be a string or array- Any other standard or custom JWT claim from the payload
equals: Exact string match (case-sensitive)contains: Value contains the match string (case-sensitive)startsWith: Value starts with the match string (case-sensitive)endsWith: Value ends with the match string (case-sensitive)regex: Regular expression matching (supports all Java regex patterns including case-insensitive matching)
Here's an example configuration with multiple rules:
{
"rules": [
{
"name": "graph-api-audience",
"claimName": "aud",
"matchType": "contains",
"matchValue": "00000003-0000-0000-c000-000000000000",
"issueName": "Graph API Audience Value Detected",
"issueDetail": "The JWT token contains a Graph API Audience: 00000003-0000-0000-c000-000000000000",
"issueBackground": "The JWT token in the Authorization header contains a Graph API Audience '00000003-0000-0000-c000-000000000000'. This specific audience value is commonly associated with Microsoft Graph API access tokens. If not intended, this could indicate potential security misconfigurations or token misuse.",
"issueRemediation": "Verify that the use of this audience value is intended for this application. If not expected, investigate potential token misuse or OAuth misconfiguration.",
"severity": "HIGH",
"enabled": true
},
{
"name": "none-algorithm",
"claimName": "alg",
"matchType": "regex",
"matchValue": "(?i)^none$",
"issueName": "JWT with 'none' Algorithm Detected",
"issueDetail": "The JWT token uses the 'none' algorithm (case-insensitive), which means it is not signed.",
"issueBackground": "The JWT token in the Authorization header uses the 'none' algorithm. This means the token is not cryptographically signed and can be easily tampered with. Using the 'none' algorithm in production environments is a critical security vulnerability as it allows attackers to forge tokens. This rule matches 'none', 'NONE', 'None', and any other case variation.",
"issueRemediation": "Ensure that all JWT tokens are properly signed using a secure algorithm such as RS256, ES256, or HS256. Never accept tokens with the 'none' algorithm in production.",
"severity": "CRITICAL",
"enabled": true
},
{
"name": "weak-hmac-algorithm",
"claimName": "alg",
"matchType": "equals",
"matchValue": "HS256",
"issueName": "JWT with HMAC Algorithm Detected",
"issueDetail": "The JWT token uses the HS256 (HMAC) algorithm for signing.",
"issueBackground": "The JWT token in the Authorization header uses the HS256 algorithm. While HMAC algorithms are not inherently insecure, they can be problematic in certain scenarios. HMAC uses a symmetric key, meaning the same key is used for both signing and verification. This can lead to security issues if the key is shared with untrusted parties or if algorithm confusion attacks are possible.",
"issueRemediation": "Consider using asymmetric algorithms like RS256 or ES256 for better security, especially in scenarios where the token verifier should not have access to the signing key. Ensure proper key management practices are in place if continuing to use HMAC.",
"severity": "MEDIUM",
"enabled": true
},
{
"name": "custom-issuer-check",
"claimName": "iss",
"matchType": "equals",
"matchValue": "https://suspicious-issuer.com",
"issueName": "Suspicious JWT Issuer Detected",
"issueDetail": "The JWT token was issued by a potentially untrusted issuer.",
"issueBackground": "The JWT token contains an issuer (iss) claim that matches a known suspicious domain. This could indicate token forgery or misconfiguration.",
"issueRemediation": "Verify the JWT issuer is the expected authorization server. Implement proper issuer validation in your application.",
"severity": "HIGH",
"enabled": false
}
]
}To create your own rules:
- Create a configuration file at
~/.burp/jwt-checker-config.json - Add rules following the format described above
- Reload the extension in Burp Suite or restart Burp
{
"rules": [
{
"name": "admin-scope-check",
"claimName": "scope",
"matchType": "contains",
"matchValue": "admin",
"issueName": "JWT with Admin Scope Detected",
"issueDetail": "Token contains administrative privileges",
"issueBackground": "The JWT token includes an 'admin' scope, granting elevated privileges.",
"issueRemediation": "Review whether this level of access is necessary and properly controlled.",
"severity": "MEDIUM",
"enabled": true
}
]
}The regex match type provides powerful pattern matching capabilities using Java's regular expression syntax. Here are common use cases and examples:
Use the (?i) flag to match regardless of case:
{
"name": "none-algorithm-any-case",
"claimName": "alg",
"matchType": "regex",
"matchValue": "(?i)none",
"issueName": "JWT with 'none' Algorithm Detected",
"issueDetail": "The JWT token uses the 'none' algorithm (any case variation)",
"issueBackground": "Matches 'none', 'NONE', 'None', 'NoNe', etc.",
"issueRemediation": "Use a secure signing algorithm.",
"severity": "HIGH",
"enabled": true
}Match any of several possible values:
{
"name": "weak-algorithms",
"claimName": "alg",
"matchType": "regex",
"matchValue": "(?i)(none|hs256|hs384|hs512)",
"issueName": "Weak or No Algorithm Detected",
"issueDetail": "JWT uses a weak symmetric algorithm or no algorithm",
"issueBackground": "The token uses HMAC or no algorithm, which may be insecure",
"issueRemediation": "Use asymmetric algorithms like RS256 or ES256",
"severity": "HIGH",
"enabled": true
}Match patterns with variable content:
{
"name": "test-environment-issuer",
"claimName": "iss",
"matchType": "regex",
"matchValue": "https?://.*\\.(test|dev|staging)\\..*",
"issueName": "Test Environment Issuer in Production",
"issueDetail": "JWT issued by a test/dev/staging environment",
"issueBackground": "The issuer URL contains test, dev, or staging subdomain",
"issueRemediation": "Ensure production uses production issuers only",
"severity": "MEDIUM",
"enabled": true
}Validate that email claims belong to specific domains:
{
"name": "external-email-domain",
"claimName": "email",
"matchType": "regex",
"matchValue": ".*@(?!yourcompany\\.com$).*",
"issueName": "External Email Domain Detected",
"issueDetail": "JWT contains email from external domain",
"issueBackground": "The email claim is not from yourcompany.com",
"issueRemediation": "Verify external users have appropriate access",
"severity": "LOW",
"enabled": true
}Match specific formats like UUIDs:
{
"name": "azure-ad-audience",
"claimName": "aud",
"matchType": "regex",
"matchValue": "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}",
"issueName": "Azure AD Audience Format Detected",
"issueDetail": "JWT audience uses UUID format typical of Azure AD",
"issueBackground": "The audience claim matches UUID pattern used by Azure AD",
"issueRemediation": "Verify the audience is the expected Azure AD resource",
"severity": "INFO",
"enabled": true
}Case-insensitive prefix matching:
{
"name": "internal-scope-prefix",
"claimName": "scope",
"matchType": "regex",
"matchValue": "(?i)^internal\\..*",
"issueName": "Internal Scope Detected",
"issueDetail": "JWT contains scope starting with 'internal.'",
"issueBackground": "Scopes with internal prefix may grant elevated access",
"issueRemediation": "Review internal scope usage and permissions",
"severity": "MEDIUM",
"enabled": true
}Match specific character patterns:
{
"name": "short-subject-id",
"claimName": "sub",
"matchType": "regex",
"matchValue": "^[0-9]{1,5}$",
"issueName": "Short Numeric Subject ID",
"issueDetail": "JWT subject is a short numeric value",
"issueBackground": "Short numeric IDs may be predictable or enumerable",
"issueRemediation": "Consider using longer, non-sequential identifiers",
"severity": "LOW",
"enabled": true
}- Escaping: Remember to escape special characters with double backslashes in JSON (e.g.,
\\.for a literal dot) - Anchors: Use
^for start of string and$for end of string - Flags: Use
(?i)for case-insensitive,(?m)for multiline - Testing: Test your regex patterns with tools like regex101.com before deployment
- Performance: Complex regex patterns may impact scanning performance; keep patterns as simple as possible
- Verify Java version (must be 17 or higher)
- Check Burp's extension output tab for error messages
- Ensure the JAR file is the
-jar-with-dependenciesversion
- Check that rules are enabled (
"enabled": true) - Verify the claim name matches exactly (case-sensitive)
- Ensure the match type and value are correct
- Check Burp's extension output tab for debugging information
- Verify the configuration file path
- Ensure the JSON is valid (use a JSON validator)
- Check file permissions
- Review Burp's extension error log
.
├── src/
│ └── main/
│ ├── java/
│ │ └── burp/
│ │ ├── JWTChecker.java # Main extension class
│ │ ├── ConfigLoader.java # Configuration loader
│ │ └── model/
│ │ ├── CheckConfig.java # Configuration model
│ │ └── Rule.java # Rule model
│ └── resources/
│ └── config.json # Default configuration
├── pom.xml # Maven configuration
└── README.md # This file
- Burp Montoya API (2025.8): Burp Suite extension API
- java-jwt (Auth0) (4.5.0): JWT decoding library
- Gson (2.13.2): JSON parsing library
- JUnit Jupiter (5.14.0): Testing framework for writing and running tests
- Mockito Core (5.20.0): Mocking framework for unit tests
- Mockito JUnit Jupiter (5.20.0): Integration between Mockito and JUnit 5
- AssertJ (3.26.3): Fluent assertions library for more readable test assertions
# Clean and compile
mvn clean compile
# Run tests (when available)
mvn test
# Package the extension
mvn package
# Clean build artifacts
mvn cleanContributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
This project is licensed under the MIT License - see the LICENSE file for details.
For issues, questions, or feature requests, please open an issue on GitHub.