~/blog
home blog projects about

Exploiting JWT Misconfigurations in Real-World Applications

August 16, 2025

TL;DR

While performing AppSec reviews on our internal products, I repeatedly encountered JWT implementations with subtle but critical misconfigurations — things like alg: none acceptance, weak or fallback secrets, algorithm confusion between symmetric and asymmetric keys, and missing claim validation. These mistakes can enable complete authentication bypass, long-lived token replay, or privilege escalation. This post walks through what I found, how I validated the issues, and practical fixes you can apply today.


🧠 Introduction

JSON Web Tokens (JWTs) are ubiquitous for stateless authentication and API authorization. Their portability and simplicity make them attractive, but those same qualities mean that small mistakes in generation or verification become powerful attack vectors.

During routine AppSec reviews of our internal services, I traced token issuance and verification logic, inspected deployment manifests, and tested token handling end-to-end. The intent of this write-up is to share concrete, realistic patterns I saw in production-like environments, how they translate into attack paths, and how teams can avoid them.


🔍 Common JWT Misconfigurations I Encounter

1) alg: none acceptance

Some verification flows did not explicitly reject tokens that declared "alg": "none". If a server accepts such tokens, an attacker can strip the signature and submit a tampered payload that the backend treats as authentic.

This is not theoretical: misconfigured verification libraries or permissive verification flags are usually the root cause.
Result: trivial authentication bypass and user impersonation.


2) Hardcoded, weak, or fallback HMAC secrets

I saw secrets present in code, example .env files, and configuration fallbacks such as "secret", "admin123", or "changeme". Worse, some services relied on an environment fallback instead of failing fast when the secret was not provided.

How I found them:


3) Asymmetric / symmetric key confusion (RS256 vs HS256)

Some services intended to use RS256 but accidentally passed the public key into HMAC verification or allowed algorithm downgrades. If the server is not strict about the algorithm, an attacker can sign a token using public key material and have it accepted. Root causes include mixing verification code across environments and reusing configuration variables incorrectly.


4) Frontend trust without server-side enforcement

Frontends parsing JWTs to decide UI state or show “admin” options without verifying the token server-side can leak sensitive information or present false privileges. While proper APIs often still enforce backend checks, client-side trust confuses threat boundaries and creates potential for information disclosure.


🧪 How I Identified & Validated These Issues

Practical steps I used during internal reviews:

All testing was done in authorized contexts against internal or staging environments per our AppSec policy ;)


🔒 Case Study: A Secret That Shouldn’t Have Been

While reviewing an internal authentication microservice as part of a scheduled AppSec review, I traced how tokens were issued and verified. In the token utility module I found:

JWT_SECRET = os.getenv("JWT_SECRET", "s3cr3t")

Using environment variables with a local fallback is common for development, but I validated the deployment pipeline and Helm chart and discovered that the production manifest did not set JWT_SECRET. The service was therefore using the fallback "s3cr3t" in production as the HMAC signing key.

To confirm the impact, I crafted a token payload with an admin role and reasonable timestamps, signed it locally using "s3cr3t", and submitted it to an admin-level API endpoint. The backend accepted the token and granted elevated privileges.

This issue was caused by multiple operational gaps:

Takeaway: Secrets must never have insecure defaults. Infrastructure-as-code and CI should enforce presence and strength of critical secrets, and services should refuse to start if essential secrets are missing.

Mitigations I applied with the team:


📌 Conclusion

JWTs are powerful tools for stateless authentication, but small implementation mistakes make them fragile. During AppSec reviews of our internal products I saw the same patterns repeat: defaults left in code, missing infrastructure checks, algorithm confusion, and lax claim validation.

Security is not a checkbox — it’s an operational discipline. Require strong configuration gating, validate everything on the backend, and bake JWT verification checks into both code and deployment pipelines. Doing so reduces the chance that a trivial oversight becomes a critical incident.


🧵 Thanks for reading! If you’re working with JWTs, take a moment to review your configs and make sure no insecure defaults are slipping through. And if you’d like to swap ideas or collaborate on building safer authentication systems, I’d love to connect.

currently online
made with ♥ by claude.ai