{"id":116,"date":"2026-11-02T20:50:16","date_gmt":"2026-11-02T15:20:16","guid":{"rendered":"https:\/\/nomorebreach.com\/blog\/?p=116"},"modified":"2026-11-02T20:55:46","modified_gmt":"2026-11-02T15:25:46","slug":"jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged","status":"publish","type":"post","link":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/","title":{"rendered":"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged"},"content":{"rendered":"<p><!-- WordPress post body. Title\/category\/tags are passed on the command line. --><\/p>\n<p>Most <strong>JWT vulnerabilities<\/strong> are not flaws in the token format. They are flaws in the few lines of code that verify it, and a token that is verified badly still looks like it works. The result is an API that accepts forged or replayed tokens while every happy-path test stays green.<\/p>\n<p><em>Last updated: 2026-11-02. CVE details and standards status below were checked against the primary sources listed at the end on that date.<\/em><\/p>\n<div class=\"key-takeaways\">\n<p><strong>Key takeaways<\/strong><\/p>\n<ul>\n<li>A signed JWT guarantees integrity, not secrecy. The signature only means something if your verifier pins the algorithm, the key, and the claims.<\/li>\n<li>Six mistakes cover most of what goes wrong: <code>alg: none<\/code>, algorithm confusion, weak HMAC secrets, trusting keys the token points to, skipping <code>iss<\/code>\/<code>aud<\/code>\/<code>typ<\/code> checks, and unpatched crypto underneath.<\/li>\n<li>Each one has shipped in real libraries or runtimes with a CVE. The standards warned about them in 2015 and 2020.<\/li>\n<li>The first fix is the same for most of them: an explicit algorithm allowlist on every verify call.<\/li>\n<li>Scanners find the obvious cases. Cross-service replay and token-type confusion need someone who understands your architecture.<\/li>\n<\/ul>\n<\/div>\n<h2>What a JWT does and does not guarantee<\/h2>\n<p>A JSON Web Token carries claims as JSON, wrapped as a signed (JWS) or encrypted (JWE) object. According to <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7519\">RFC 7519<\/a>, the format was published in May 2015.<\/p>\n<p>Most API tokens are signed, not encrypted. A signed token is base64url encoded, so anyone who holds it can read the payload. As the <a href=\"https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/JSON_Web_Token_Cheat_Sheet.html\">OWASP JSON Web Token Cheat Sheet<\/a> notes, keep sensitive data out of it.<\/p>\n<p>What you get is integrity: the contents were not changed after issue. You only get that if the verifier is strict about which algorithm, which key, and which claims it accepts. <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8725\">RFC 8725<\/a> (the JWT Best Current Practices) exists because libraries left those choices to the caller. Every mistake below lives in that gap.<\/p>\n<h2>Mistake 1: letting the token choose <code>alg: none<\/code><\/h2>\n<p>The JWT header names the algorithm used to sign the token. One legal value is <code>none<\/code>, an unsecured token with no signature at all. <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7518\">RFC 7518<\/a> (section 3.6) says implementations &#8220;MUST NOT accept Unsecured JWSs by default.&#8221;<\/p>\n<p>If your verify call lets the token&#8217;s header decide, an attacker can strip the signature and your API may still accept it.<\/p>\n<p>This shipped in practice. According to <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-23540\">CVE-2022-23540<\/a>, <code>jsonwebtoken<\/code> for Node, versions up to 8.5.1, could default to <code>none<\/code> when <code>verify()<\/code> was called without an <code>algorithms<\/code> option. It was fixed in 9.0.0. NVD scores it 7.6 and the GitHub CNA scores it 6.4.<\/p>\n<p>Blocklists do not save you. The <a href=\"https:\/\/github.com\/OWASP\/wstg\/blob\/master\/document\/4-Web_Application_Security_Testing\/06-Session_Management\/10-JSON_Web_Tokens.md\">OWASP testing guide (WSTG-SESS-10)<\/a> tells testers to try case variants of <code>none<\/code> against case-insensitive filters.<\/p>\n<p>The standards are tightening further. The IETF working-group draft <a href=\"https:\/\/datatracker.ietf.org\/doc\/draft-ietf-oauth-rfc8725bis\/\">rfc8725bis<\/a> (a draft, not yet an RFC) would add a MUST for applications to opt in explicitly to <code>none<\/code>.<\/p>\n<p><strong>How to check:<\/strong> find every verify and decode call in your codebase. Each one should pass an explicit list of allowed algorithms.<\/p>\n<h2>Mistake 2: algorithm confusion (RS256 key used as an HS256 secret)<\/h2>\n<p>Here the server expects an asymmetric algorithm such as RS256. The attacker sends a token that claims <code>HS256<\/code>, signed using the server&#8217;s <em>public<\/em> key as the HMAC secret. Public keys are, by design, public. A naive library sees &#8220;HS256&#8221;, takes the key you gave it, and the signature checks out.<\/p>\n<p>This is the oldest repeat offender in the JWT world:<\/p>\n<ul>\n<li><a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2015-9235\">CVE-2015-9235<\/a>: <code>jsonwebtoken<\/code> before 4.2.2. NVD rates it CVSS 3.0 9.8.<\/li>\n<li><a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-29217\">CVE-2022-29217<\/a>: PyJWT, fixed in 2.4.0. The documented workaround is an explicit algorithm list. NVD rates it 7.5.<\/li>\n<li><a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-23541\">CVE-2022-23541<\/a>: <code>jsonwebtoken<\/code> up to 8.5.1, a key-retrieval misconfiguration issue. NVD rates it 6.3.<\/li>\n<li><a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2024-54150\">CVE-2024-54150<\/a>: cjwt, a C library, published December 2024. It is still happening.<\/li>\n<\/ul>\n<p>RFC 8725 (section 3.1) says libraries MUST let callers specify allowed algorithms, and that each key should be used with exactly one algorithm. OWASP&#8217;s guidance is the same: do not mix public-key and MAC algorithms in one verifier.<\/p>\n<p><strong>How to check:<\/strong> confirm each key maps to exactly one algorithm in code, and that a token claiming a different one is rejected.<\/p>\n<h2>Mistake 3: a guessable HMAC secret<\/h2>\n<p>With HS256, anyone who captures one valid token can try guesses against it offline. There is no login endpoint to rate-limit and nothing to lock out. RFC 8725 (section 2.2) describes this directly. A weak secret turns into a forged-token factory.<\/p>\n<p>The rules are clear:<\/p>\n<ul>\n<li>RFC 7518 (section 3.2): the key MUST be at least as long as the hash output, which is 256 bits for HS256.<\/li>\n<li>RFC 8725 (section 3.5): human-memorable passwords MUST NOT be used directly as HMAC keys.<\/li>\n<li>OWASP: at least 160 bits of entropy from a cryptographically secure random generator, and no reuse across issuers, audiences, or purposes.<\/li>\n<\/ul>\n<p>The failure pattern we look for is mundane: a placeholder such as <code>secret<\/code> or <code>changeme<\/code>, a framework&#8217;s example value, or a <code>.env.example<\/code> that made it to production. We are describing a pattern, not quoting a statistic.<\/p>\n<p><strong>How to check:<\/strong> read your production signing key&#8217;s source. If a person typed it, replace it with a random value of at least 256 bits and use a different one per service.<\/p>\n<h2>Mistake 4: trusting keys the token points to<\/h2>\n<p>JWT headers can carry hints about which key to use: <code>jwk<\/code> (an embedded key), <code>jku<\/code> and <code>x5u<\/code> (URLs to fetch keys from), and <code>kid<\/code> (a key identifier). Every one of those is attacker-controlled input.<\/p>\n<p>The clearest real case is <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2018-0114\">CVE-2018-0114<\/a>. Cisco&#8217;s <code>node-jose<\/code> before 0.11.0 trusted a public key embedded in the token header, so an attacker could re-sign tokens with their own key. NVD rates it 7.5.<\/p>\n<p>The other three fail in different ways, according to the OWASP testing guide and RFC 8725 (section 3.10):<\/p>\n<ul>\n<li><code>kid<\/code> used in a file path or a database lookup opens the door to path traversal or injection.<\/li>\n<li><code>jku<\/code> and <code>x5u<\/code> make your server fetch a URL the attacker chose. That is forgery plus server-side request forgery.<\/li>\n<li>The RFC&#8217;s advice is to sanitise <code>kid<\/code> and allowlist any <code>jku<\/code>\/<code>x5u<\/code> hosts.<\/li>\n<\/ul>\n<p><strong>How to check:<\/strong> keys should come from your server config, or from a pinned key-set URL for an issuer you already trust. Never from the token itself.<\/p>\n<h2>Mistake 5: valid signature, wrong token<\/h2>\n<p>A perfect signature proves who issued the token. It does not prove the token was meant for <em>this<\/em> API, or that it is the <em>kind<\/em> of token you expect.<\/p>\n<h3>Replay across services<\/h3>\n<p>Say one identity-provider tenant issues tokens for several apps and APIs. If your API never checks the audience (<code>aud<\/code>) claim, a token minted for service A is accepted by service B. RFC 8725 (section 3.9) says that when multiple relying parties share an issuer, <code>aud<\/code> MUST be present and checked.<\/p>\n<p>This is an integration mistake, not a vendor bug. It is easy to make with any identity provider.<\/p>\n<h3>Confusing token types<\/h3>\n<p>ID tokens, email-verification tokens, and refresh tokens are all JWTs too. If your API accepts any validly signed token, one of those can be presented as an access token. RFC 8725 (sections 3.11 and 3.12) recommends explicit <code>typ<\/code> values and mutually exclusive validation rules. <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9068\">RFC 9068<\/a> defines <code>typ: at+jwt<\/code> for OAuth access tokens, and resource servers should reject other types.<\/p>\n<h3>Library gotchas<\/h3>\n<p>Per the OWASP cheat sheet, PyJWT needs the <code>issuer=<\/code> and <code>audience=<\/code> arguments to actually compare values. The <code>verify_iss<\/code>\/<code>verify_aud<\/code> options alone do not. Also pick keys only from the matched issuer&#8217;s key set, never a union across issuers.<\/p>\n<p><strong>How to check:<\/strong> take a valid token from one service and send it to another. Then try an ID or refresh token on a protected route. Both should fail.<\/p>\n<h2>Mistake 6: assuming the crypto underneath is correct<\/h2>\n<p>Sometimes your code is right and the runtime is wrong. <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-21449\">CVE-2022-21449<\/a> (&#8220;psychic signatures&#8221;) let Java&#8217;s ECDSA implementation accept a signature with <code>r = s = 0<\/code> for any message. ES256 JWTs verified by an affected JVM could be forged. NVD rates it 7.5 and lists Java SE 17.0.2 and 18 as affected.<\/p>\n<p>The researcher who found it reports a wider range, Java 15 to 18, fixed in the April 2022 Critical Patch Update, and says he reported it to OpenJDK on 11 November 2021. That account is <a href=\"https:\/\/neilmadden.blog\/2022\/04\/19\/psychic-signatures-in-java\/\">his own write-up<\/a>. We cite NVD for the affected versions and treat the wider range as reported.<\/p>\n<p>The lesson is practical. Patching the runtime and the JWT library is part of auth security. And your tests need negative cases: forged and malformed tokens must fail, not just valid ones succeed.<\/p>\n<h2>What a correct verify call looks like<\/h2>\n<p>Here is the defensive version in Python with PyJWT 2.4.0 or later. The key comes from config, the algorithm is pinned, and the claims are required.<\/p>\n<pre><code>import jwt  # PyJWT &gt;= 2.4.0\n\nclaims = jwt.decode(\n    token,\n    key=public_key,                      # from config \/ pinned JWKS for THIS issuer\n    algorithms=[\"RS256\"],                # explicit allowlist; never read from the token\n    audience=\"https:\/\/api.example.com\",  # this service only\n    issuer=\"https:\/\/auth.example.com\",   # exact match\n    options={\"require\": [\"exp\", \"iss\", \"aud\"]},\n)\n# Then: check header typ == \"at+jwt\" (if your IdP issues RFC 9068 tokens)\n# and authorize the specific object being requested.<\/code><\/pre>\n<p>The Node equivalent on <code>jsonwebtoken<\/code> 9.0.0 or later is <code>jwt.verify(token, key, { algorithms: ['RS256'], audience, issuer })<\/code>.<\/p>\n<p>Note the last comment. A valid token with a missing object-level check is the next bug in line. That is the classic IDOR pattern: the app knows who you are but never asks whether this object is yours.<\/p>\n<h2>Revocation, theft, and what &ldquo;stateless&rdquo; costs you<\/h2>\n<p>A JWT is valid until its <code>exp<\/code> time. Revoking one early means keeping a denylist keyed on <code>jti<\/code> plus issuer (not the raw token) or a status list. OWASP is clear that either one brings state back.<\/p>\n<p>That is a trade-off, not a reason to avoid JWTs:<\/p>\n<ul>\n<li><strong>Keep access tokens short-lived,<\/strong> and rotate refresh tokens.<\/li>\n<li><strong>Sender-constrain high-value tokens.<\/strong> <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9449\">RFC 9449 (DPoP)<\/a> or mutual TLS makes a stolen token useless without the client&#8217;s key.<\/li>\n<li><strong>Use the current reference.<\/strong> <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9700\">RFC 9700<\/a> (January 2025) is the OAuth 2.0 security best practice for token handling.<\/li>\n<li><strong>Consider not using JWTs at all<\/strong> for a single first-party web app. OWASP suggests an opaque server-side session can be simpler and safer there.<\/li>\n<\/ul>\n<h2>JWT security best practices, in priority order<\/h2>\n<p>This is the order we would fix things, cheapest and highest-impact first.<\/p>\n<ol>\n<li><strong>Pin the algorithm on every verify call,<\/strong> one algorithm per key. Cost is trivial. It only breaks things if you were quietly accepting mixed algorithms.<\/li>\n<li><strong>Upgrade.<\/strong> <code>jsonwebtoken<\/code> 9.0.0 or later, PyJWT 2.4.0 or later, and a patched JDK.<\/li>\n<li><strong>Prefer asymmetric signing when more than one service verifies tokens<\/strong> (RS256, ES256, or EdDSA). If you stay on HS256, use a random secret of at least 256 bits that is not shared across services. The trade-off: asymmetric means you operate key-set rotation and caching.<\/li>\n<li><strong>Take keys from config or a pinned key set only.<\/strong> Ignore <code>jwk<\/code>\/<code>x5c<\/code> in headers, allowlist <code>jku<\/code>\/<code>x5u<\/code>, and treat <code>kid<\/code> as untrusted input.<\/li>\n<li><strong>Require and check <code>exp<\/code>, <code>iss<\/code>, <code>aud<\/code>,<\/strong> plus <code>typ<\/code> where your provider sets it.<\/li>\n<li><strong>Shorten token lifetime,<\/strong> and add DPoP or mutual TLS for high-value APIs. The cost is client complexity and key management.<\/li>\n<li><strong>Add negative tests to CI.<\/strong> Tokens with <code>none<\/code>, the wrong algorithm, the wrong audience, an expired time, or the wrong type must all be rejected.<\/li>\n<\/ol>\n<h2>How long this has been known<\/h2>\n<table>\n<thead>\n<tr>\n<th>Date<\/th>\n<th>Event<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>May 2015<\/td>\n<td>RFC 7518\/7519 published; <code>none<\/code> must not be accepted by default<\/td>\n<\/tr>\n<tr>\n<td>2015 (NVD entry 2018-05-29)<\/td>\n<td><code>jsonwebtoken<\/code> algorithm confusion, CVE-2015-9235<\/td>\n<\/tr>\n<tr>\n<td>2018-01-04<\/td>\n<td><code>node-jose<\/code> embedded key, CVE-2018-0114<\/td>\n<\/tr>\n<tr>\n<td>Feb 2020<\/td>\n<td>RFC 8725, JWT Best Current Practices (BCP 225)<\/td>\n<\/tr>\n<tr>\n<td>2022-04-19<\/td>\n<td>Java &ldquo;psychic signatures&rdquo;, CVE-2022-21449<\/td>\n<\/tr>\n<tr>\n<td>2022-05-24<\/td>\n<td>PyJWT algorithm confusion, CVE-2022-29217<\/td>\n<\/tr>\n<tr>\n<td>2022-12-22<\/td>\n<td><code>jsonwebtoken<\/code> 9.0.0 fixes, CVE-2022-23540 and CVE-2022-23541<\/td>\n<\/tr>\n<tr>\n<td>2024-12-19<\/td>\n<td>cjwt algorithm confusion, CVE-2024-54150<\/td>\n<\/tr>\n<tr>\n<td>Jan 2025<\/td>\n<td>RFC 9700, OAuth 2.0 Security BCP<\/td>\n<\/tr>\n<tr>\n<td>Aug 2026<\/td>\n<td>rfc8725bis-10, an IETF draft submitted to the IESG<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>How we test JWT handling<\/h2>\n<p>Our API and authentication testing follows the same sequence as the OWASP testing guide: decode the token, tamper with the algorithm, try algorithm confusion, test the secret&#8217;s strength, inject into header fields, and replay claims across services.<\/p>\n<p>In our opinion, automated scanners are good at the first few and weak at the last. Cross-service <code>aud<\/code> replay and token-type confusion depend on knowing which services share an issuer and which token types your architecture issues. That needs a human who has read your design.<\/p>\n<p>If your agent or MCP backends authenticate with JWT bearer tokens, the same checks apply there.<\/p>\n<h2>FAQ<\/h2>\n<h3>Is a JWT encrypted?<\/h3>\n<p>No. A signed JWT is only base64url encoded, so anyone who holds it can read the payload. The signature proves it was not altered. It does not hide anything. Keep secrets and personal data out of the claims, or use an encrypted token (JWE) when confidentiality matters.<\/p>\n<h3>What is the JWT &ldquo;alg: none&rdquo; attack?<\/h3>\n<p>The attacker sets the token&#8217;s algorithm to <code>none<\/code> and removes the signature. If the verifier lets the token choose its own algorithm, it may accept the forged token. RFC 7518 says implementations must not accept unsecured tokens by default. Always pass an explicit algorithm allowlist when verifying.<\/p>\n<h3>What is JWT algorithm confusion (RS256 vs HS256)?<\/h3>\n<p>The server expects an asymmetric algorithm like RS256, but the attacker sends a token marked HS256 and signed with the server&#8217;s public key as the HMAC secret. A naive library verifies it. The fix is to pin one algorithm per key, as RFC 8725 requires.<\/p>\n<h3>How long should a JWT HMAC secret be?<\/h3>\n<p>At least as long as the hash output: 256 bits for HS256, according to RFC 7518. OWASP asks for at least 160 bits of entropy from a secure random generator. Never use a memorable password, and do not reuse one secret across services or purposes.<\/p>\n<h3>Which claims must I validate in a JWT?<\/h3>\n<p>Check <code>exp<\/code> so expired tokens fail, <code>iss<\/code> for the expected issuer, and <code>aud<\/code> so the token was meant for your API. Where your provider sets it, also check <code>typ<\/code> so an ID or refresh token cannot pass as an access token. Make the library require them.<\/p>\n<h3>Can you revoke a JWT?<\/h3>\n<p>Not by itself. A JWT stays valid until <code>exp<\/code>. To revoke early you need a denylist keyed on <code>jti<\/code> and issuer, or a status list, which reintroduces server-side state. Most teams keep access tokens short-lived, rotate refresh tokens, and sender-constrain sensitive tokens with DPoP or mutual TLS.<\/p>\n<h2>Sources<\/h2>\n<ul>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7519\">RFC 7519, JSON Web Token<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7518\">RFC 7518, JSON Web Algorithms<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8725\">RFC 8725, JWT Best Current Practices<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9068\">RFC 9068, JWT Profile for OAuth 2.0 Access Tokens<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9449\">RFC 9449, OAuth 2.0 DPoP<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9700\">RFC 9700, Best Current Practice for OAuth 2.0 Security<\/a><\/li>\n<li><a href=\"https:\/\/datatracker.ietf.org\/doc\/draft-ietf-oauth-rfc8725bis\/\">IETF draft-ietf-oauth-rfc8725bis<\/a><\/li>\n<li><a href=\"https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/JSON_Web_Token_Cheat_Sheet.html\">OWASP JSON Web Token Cheat Sheet<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/OWASP\/wstg\/blob\/master\/document\/4-Web_Application_Security_Testing\/06-Session_Management\/10-JSON_Web_Tokens.md\">OWASP WSTG-SESS-10, Testing JSON Web Tokens<\/a><\/li>\n<li>NVD: <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2015-9235\">CVE-2015-9235<\/a>, <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2018-0114\">CVE-2018-0114<\/a>, <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-21449\">CVE-2022-21449<\/a>, <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-23540\">CVE-2022-23540<\/a>, <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-23541\">CVE-2022-23541<\/a>, <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-29217\">CVE-2022-29217<\/a>, <a href=\"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2024-54150\">CVE-2024-54150<\/a><\/li>\n<li>Reported by the discoverer: <a href=\"https:\/\/neilmadden.blog\/2022\/04\/19\/psychic-signatures-in-java\/\">Psychic Signatures in Java<\/a><\/li>\n<\/ul>\n<hr>\n<p><strong>Want us to check how your API actually verifies tokens?<\/strong> <a href=\"https:\/\/nomorebreach.com\/contact.html\">Book a scoping call<\/a> and we will map an API and authentication pentest to your stack. See what we test on our <a href=\"https:\/\/nomorebreach.com\/products.html\">services page<\/a>. Not ready to talk? Start with a free external attack-surface snapshot, no access needed: <a href=\"https:\/\/nomorebreach.com\/#snapshot\">nomorebreach.com<\/a>.<\/p>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\/jku injection, and missing claim checks.<\/p>\n","protected":false},"author":1,"featured_media":117,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40],"tags":[57,42,58,56,46],"class_list":["post-116","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-appsec","tag-api-security","tag-appsec","tag-authentication","tag-jwt","tag-penetration-testing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged - NoMoreBreach Insights<\/title>\n<meta name=\"description\" content=\"Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\/jku injection, and missing claim checks\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged - NoMoreBreach Insights\" \/>\n<meta property=\"og:description\" content=\"Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\/jku injection, and missing claim checks\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/\" \/>\n<meta property=\"og:site_name\" content=\"NoMoreBreach Insights\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-02T15:20:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-11-02T15:25:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2026\/11\/jwt-vulnerabilities-how-to-check-your-api.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"nomorebreachofficial\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@NoMoreBreachSec\" \/>\n<meta name=\"twitter:site\" content=\"@nomorebreach\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"nomorebreachofficial\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/\"},\"author\":{\"name\":\"nomorebreachofficial\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#\\\/schema\\\/person\\\/bb2410510214ded6aa0305e6ff04de94\"},\"headline\":\"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged\",\"datePublished\":\"2026-11-02T15:20:16+00:00\",\"dateModified\":\"2026-11-02T15:25:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/\"},\"wordCount\":2314,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/jwt-vulnerabilities-how-to-check-your-api.png\",\"keywords\":[\"api-security\",\"appsec\",\"authentication\",\"jwt\",\"penetration-testing\"],\"articleSection\":[\"AppSec\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/\",\"url\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/\",\"name\":\"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged - NoMoreBreach Insights\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/jwt-vulnerabilities-how-to-check-your-api.png\",\"datePublished\":\"2026-11-02T15:20:16+00:00\",\"dateModified\":\"2026-11-02T15:25:46+00:00\",\"description\":\"Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\\\/jku injection, and missing claim checks\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#primaryimage\",\"url\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/jwt-vulnerabilities-how-to-check-your-api.png\",\"contentUrl\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/jwt-vulnerabilities-how-to-check-your-api.png\",\"width\":1200,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/\",\"name\":\"No More Breach Insights\",\"description\":\"Stop Threats Before They Start\",\"publisher\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#organization\",\"name\":\"No More Breach\",\"url\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/01\\\/Untitled_design-removebg-preview.png\",\"contentUrl\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/01\\\/Untitled_design-removebg-preview.png\",\"width\":500,\"height\":500,\"caption\":\"No More Breach\"},\"image\":{\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/nomorebreach\",\"https:\\\/\\\/instagram.com\\\/nomorebreach\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/#\\\/schema\\\/person\\\/bb2410510214ded6aa0305e6ff04de94\",\"name\":\"nomorebreachofficial\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6d4a84f25c82ed978512f73233e5c099b060eb4a2a74d789a240c355d0e280f4?s=96&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6d4a84f25c82ed978512f73233e5c099b060eb4a2a74d789a240c355d0e280f4?s=96&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6d4a84f25c82ed978512f73233e5c099b060eb4a2a74d789a240c355d0e280f4?s=96&r=g\",\"caption\":\"nomorebreachofficial\"},\"description\":\"The NoMoreBreach team helps startups and businesses find and fix security gaps before attackers do. We write practical, no-hype guides on real vulnerabilities, misconfigurations and attack techniques, each checked against primary sources and turned into steps you can act on. Want to see what attackers can see? Request a free external attack-surface snapshot at nomorebreach.com.\",\"sameAs\":[\"https:\\\/\\\/nomorebreach.com\\\/blog\",\"https:\\\/\\\/instagram.com\\\/nomorebreach\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/nomorebreach\",\"https:\\\/\\\/x.com\\\/NoMoreBreachSec\"],\"url\":\"https:\\\/\\\/nomorebreach.com\\\/blog\\\/author\\\/nomorebreachofficial\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged - NoMoreBreach Insights","description":"Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\/jku injection, and missing claim checks","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/","og_locale":"en_US","og_type":"article","og_title":"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged - NoMoreBreach Insights","og_description":"Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\/jku injection, and missing claim checks","og_url":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/","og_site_name":"NoMoreBreach Insights","article_published_time":"2026-11-02T15:20:16+00:00","article_modified_time":"2026-11-02T15:25:46+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2026\/11\/jwt-vulnerabilities-how-to-check-your-api.png","type":"image\/png"}],"author":"nomorebreachofficial","twitter_card":"summary_large_image","twitter_creator":"@NoMoreBreachSec","twitter_site":"@nomorebreach","twitter_misc":{"Written by":"nomorebreachofficial","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#article","isPartOf":{"@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/"},"author":{"name":"nomorebreachofficial","@id":"https:\/\/nomorebreach.com\/blog\/#\/schema\/person\/bb2410510214ded6aa0305e6ff04de94"},"headline":"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged","datePublished":"2026-11-02T15:20:16+00:00","dateModified":"2026-11-02T15:25:46+00:00","mainEntityOfPage":{"@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/"},"wordCount":2314,"commentCount":0,"publisher":{"@id":"https:\/\/nomorebreach.com\/blog\/#organization"},"image":{"@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#primaryimage"},"thumbnailUrl":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2026\/11\/jwt-vulnerabilities-how-to-check-your-api.png","keywords":["api-security","appsec","authentication","jwt","penetration-testing"],"articleSection":["AppSec"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/","url":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/","name":"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged - NoMoreBreach Insights","isPartOf":{"@id":"https:\/\/nomorebreach.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#primaryimage"},"image":{"@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#primaryimage"},"thumbnailUrl":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2026\/11\/jwt-vulnerabilities-how-to-check-your-api.png","datePublished":"2026-11-02T15:20:16+00:00","dateModified":"2026-11-02T15:25:46+00:00","description":"Six JWT mistakes that let attackers forge or replay tokens: alg none, algorithm confusion, weak secrets, kid\/jku injection, and missing claim checks","breadcrumb":{"@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#primaryimage","url":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2026\/11\/jwt-vulnerabilities-how-to-check-your-api.png","contentUrl":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2026\/11\/jwt-vulnerabilities-how-to-check-your-api.png","width":1200,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/nomorebreach.com\/blog\/jwt-vulnerabilities-6-mistakes-that-let-tokens-be-forged\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nomorebreach.com\/blog\/"},{"@type":"ListItem","position":2,"name":"JWT Vulnerabilities: 6 Mistakes That Let Tokens Be Forged"}]},{"@type":"WebSite","@id":"https:\/\/nomorebreach.com\/blog\/#website","url":"https:\/\/nomorebreach.com\/blog\/","name":"No More Breach Insights","description":"Stop Threats Before They Start","publisher":{"@id":"https:\/\/nomorebreach.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/nomorebreach.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/nomorebreach.com\/blog\/#organization","name":"No More Breach","url":"https:\/\/nomorebreach.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nomorebreach.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2025\/01\/Untitled_design-removebg-preview.png","contentUrl":"https:\/\/nomorebreach.com\/blog\/wp-content\/uploads\/2025\/01\/Untitled_design-removebg-preview.png","width":500,"height":500,"caption":"No More Breach"},"image":{"@id":"https:\/\/nomorebreach.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/nomorebreach","https:\/\/instagram.com\/nomorebreach"]},{"@type":"Person","@id":"https:\/\/nomorebreach.com\/blog\/#\/schema\/person\/bb2410510214ded6aa0305e6ff04de94","name":"nomorebreachofficial","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/6d4a84f25c82ed978512f73233e5c099b060eb4a2a74d789a240c355d0e280f4?s=96&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/6d4a84f25c82ed978512f73233e5c099b060eb4a2a74d789a240c355d0e280f4?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d4a84f25c82ed978512f73233e5c099b060eb4a2a74d789a240c355d0e280f4?s=96&r=g","caption":"nomorebreachofficial"},"description":"The NoMoreBreach team helps startups and businesses find and fix security gaps before attackers do. We write practical, no-hype guides on real vulnerabilities, misconfigurations and attack techniques, each checked against primary sources and turned into steps you can act on. Want to see what attackers can see? Request a free external attack-surface snapshot at nomorebreach.com.","sameAs":["https:\/\/nomorebreach.com\/blog","https:\/\/instagram.com\/nomorebreach","https:\/\/www.linkedin.com\/company\/nomorebreach","https:\/\/x.com\/NoMoreBreachSec"],"url":"https:\/\/nomorebreach.com\/blog\/author\/nomorebreachofficial\/"}]}},"_links":{"self":[{"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/posts\/116","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/comments?post=116"}],"version-history":[{"count":2,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/posts\/116\/revisions"}],"predecessor-version":[{"id":120,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/posts\/116\/revisions\/120"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/media\/117"}],"wp:attachment":[{"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/media?parent=116"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/categories?post=116"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nomorebreach.com\/blog\/wp-json\/wp\/v2\/tags?post=116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}