JWTs: A Comedy of Errors and Exploits

3 hours ago 3
BOOK THIS SPACE FOR AD
ARTICLE AD

Jack Havoltrey

source: The wonderful people at portswigger

Ah, the JSON Web Token — JWT for short. A harmless little format, they say. But isn’t that what they always say about the most dangerous toys? You see, JWT isn’t just one thing; it’s a concept. It can take on the form of a JWS or a JWE. Think of it like a letter: formal or informal, polite or scathing — it’s all about the delivery. And in the world of security, JWS is the star of the show.

Now, JWTs are supposed to be secure. Supposed to be. But the real punchline? It’s never the JWT itself that’s the problem — it’s the bumbling developers who twist and break it like a cheap prop. Let’s explore their comedy of errors, shall we?

Imagine this: you walk into a bank, hand over a check, and they cash it without even glancing at the signature. Sounds absurd, doesn’t it? Well, welcome to the world of unverified JWT signature vulnerabilities! Some developers, in their infinite wisdom, decode JWTs without bothering to verify the signature. This little oversight lets attackers edit claims and waltz right into accounts they don’t own. A quick edit, a payload tweak, and boom — account takeover!

And then there’s the pièce de résistance: the "alg": "none" trick. Yes, you read that right. Some servers will happily accept a JWT with no signature at all if the header claims it was signed with none.

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

Oh, but don’t forget — the payload still needs a trailing dot. A dot! The developers enforce that rule, but verifying signatures? Nah, that’s too much work. With a little obfuscation — mixing capitalization, and unexpected encodings — you can slip right past their filters. Bravo!

Then there are the algorithms that rely on secret keys. Sounds secure, right? Until some copy-pasting genius forgets to replace the default key from the tutorial they googled at 3 a.m. Want to crack these secrets? Fire up Hashcat and let the brute force begin:

hashcat -a 0 -m 16500 <jwt> <wordlist>

Here’s where things get really fun. With asymmetric JWTs, you’ve got public-private key pairs. But instead of retaining any semblance of control, some developers let the client dictate everything. Embed a jwk header with your public key, sign the JWT with your private key, and voila! The server verifies the token against your key.

{
"kid": "chaos-key",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"n": "chaotic-public-key"
}
}

Don’t feel like embedding the key? No problem. Just point the server to your custom JWK set using the jku parameter. A little SSRF magic, and now the server is dancing to your tune.

And let’s not forget the good old kid parameter. Some developers decide it’s a great idea to let this parameter specify a file path. You know where this is going, don’t you? A little path traversal, and suddenly the server’s verifying your token against /dev/null. Empty file, empty security. And if that kid points to a database entry? Oh, the possibilities for SQL injection!

Finally, we have the algorithm confusion attack. The server expects asymmetric signatures but doesn’t mind if you switch to a symmetric algorithm. Sign the JWT yourself, trick the server into verifying it with the public key, and laugh all the way to the exploit bank.

So, there you have it — the wonderful, absurd world of JWT vulnerabilities. They say the devil’s in the details, but here? The devil’s in the developer’s oversight. Go ahead, tighten your algorithms, sanitize your inputs, and verify those signatures. But remember — every lock has a key, and every system has a flaw. You just have to find it. Let’s see who gets the last laugh!

Read Entire Article