JSON Web Tokens are everywhere: APIs, user sessions, SSO. And when servers implement them poorly, they become a direct backdoor into privileged accounts.

In this walkthrough, we'll solve the "JWT authentication bypass via unverified signature" lab from PortSwigger Web Security Academy using HackUtils — a 100% client-side tool that runs entirely in your browser without sending your tokens to any external server.

What vulnerability are we exploiting?

Some servers decode JWTs to read claims (like sub or role), but never verify that the signature is valid. This means you can freely modify the payload — change your username to administrator, for example — and the server will accept it without question.

It's one of the simplest and most critical JWT vulnerabilities that exist.

Setup: The Lab

We activate the lab on PortSwigger. Objective: access the /admin panel and delete the user carlos.

Link: https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-unverified-signature

None

Credentials provided by the lab: wiener:peter. A regular user with no admin privileges.

Step 1: Login and JWT Interception

We navigate to /login, enter the credentials, and leave Burp with Intercept on.

None

After a successful login, the server redirects us to /my-account and we are authenticated as wiener.

None

Now we look at the POST /login response in Burp. In the Set-Cookie header we find the session JWT:

None

We copy that token. It contains all the session information, signed (or supposedly signed) by the server.

Step 2: Decode the JWT in HackUtils

We open hackutils.com, go to the JWT Decoder section, and paste the token.

None

At a glance we can already see the most important details:

  • SUBJECT (SUB): wiener — our current user
  • EXPIRATION (EXP): human-readable date, no need to manually convert the epoch timestamp
  • ISSUER (ISS): portswigger

Scrolling down we see the full Header and Payload:

None

We can see:

// Header
{
  "kid": "2ab73edc-4a61-4b5c-a9ae-e46514d5880f",
  "alg": "RS256"
}
// Payload
{
  "iss": "portswigger",
  "exp": 1772177891,
  "sub": "wiener"
}

The algorithm is RS256 (asymmetric RSA). Under normal conditions, modifying the payload would invalidate the signature because we don't have the private key. But remember: this server never verifies the signature. It doesn't matter what's in it.

Step 3: Modify the sub Claim

The Header and Payload panels in HackUtils are directly editable — no copying, no pasting into a separate editor.

We click on the "sub" field in the Payload and change it:

"sub": "wiener"  →  "sub": "administrator"
None

Now we click Rebuild & Verify. HackUtils reconstructs the token with the modified payload. The signature in the third part of the JWT will be outdated — but that doesn't matter because the server doesn't validate it.

None

We copy the modified token.

Step 4: Replace the Token and Access /admin

Back in Burp, we try to access /admin with our original token. The server blocks access:

None

We intercept the GET /admin request in Burp and replace the session cookie value with our modified token.

None

We forward the request. The server reads the claim "sub": "administrator", skips signature verification, and grants us access to the admin panel.

Step 5: Delete carlos

Inside the admin panel we see the user list: wiener and carlos. We click Delete next to carlos.

None

The request goes through with our forged admin token. The server accepts it.

Lab Solved ✅

None

Why HackUtils instead of jwt.io?

When you're on a real engagement, the JWT you intercept may contain sensitive production data: real user IDs, roles, session data. Pasting it into jwt.io means sending it to a third-party server.

HackUtils processes everything in your browser. The token never leaves your machine. For a professional pentester, that's not a minor detail.

Beyond privacy, HackUtils also offers things jwt.io doesn't:

  • Automatically converts iat/exp timestamps to human-readable dates
  • Built-in alg:none attack with all bypass variants ready to copy
  • Header and Payload are editable directly in the same interface
  • No account or registration required — just open and use

Conclusion

This vulnerability is a reminder that signing a JWT is not enough — the server must verify that signature on every single request. If it doesn't, the token is about as secure as plain text.

The lab is rated Apprentice for a reason: the exploit is trivial. Change a string in an editable field and copy the result. But in the real world, this kind of misconfiguration shows up in production applications more often than you'd expect.

Try HackUtils on your next engagement: hackutils.com

Written by @stuxboynet

Tags: Penetration Testing JWT Web Security PortSwigger Ethical Hacking Bug Bounty Red Team OSCP Hack Cybersecurity