{"record":{"id":"e051fb1069496e97","repo":"jwtk/jjwt","slug":"unsecured-jwss-those-with-an-alg-header-value-of-e051fb","errorCode":null,"errorMessage":"Unsecured JWSs (those with an alg header value of 'none') may not use the crit header parameter per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11 (\"the [crit] Header Parameter MUST be integrity protected; therefore, it MUST occur only within [a] JWS Protected Header)\". Header: %s","messagePattern":"Unsecured JWSs \\(those with an alg header value of 'none'\\) may not use the crit header parameter per https://www\\.rfc-editor\\.org/rfc/rfc7515\\.html#section-4\\.1\\.11 \\(\"the \\[crit\\] Header Parameter MUST be integrity protected; therefore, it MUST occur only within \\[a\\] JWS Protected Header\\)\"\\. Header: (.+?)","errorType":"exception","errorClass":"MalformedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":421,"sourceCode":"        final boolean unsecured = Jwts.SIG.NONE.getId().equalsIgnoreCase(alg);\n\n        final CharSequence base64UrlDigest = tokenized.getDigest();\n        final boolean hasDigest = Strings.hasText(base64UrlDigest);\n        if (unsecured) {\n            if (tokenized instanceof TokenizedJwe) {\n                throw new MalformedJwtException(JWE_NONE_MSG);\n            }\n            // Unsecured JWTs are disabled by default per the RFC:\n            if (!this.unsecured) {\n                String msg = UNSECURED_DISABLED_MSG_PREFIX + header;\n                throw new UnsupportedJwtException(msg);\n            }\n            if (hasDigest) {\n                throw new MalformedJwtException(JWS_NONE_SIG_MISMATCH_MSG);\n            }\n            if (header.containsKey(DefaultProtectedHeader.CRIT.getId())) {\n                String msg = String.format(CRIT_UNSECURED_MSG, header);\n                throw new MalformedJwtException(msg);\n            }\n        } else if (!hasDigest) { // something other than 'none'.  Must have a digest component:\n            String fmt = tokenized instanceof TokenizedJwe ? MISSING_JWE_DIGEST_MSG_FMT : MISSING_JWS_DIGEST_MSG_FMT;\n            String msg = String.format(fmt, alg);\n            throw new MalformedJwtException(msg);\n        }\n        // ----- crit assertions -----\n        if (header instanceof ProtectedHeader) {\n            Set<String> crit = Collections.nullSafe(((ProtectedHeader) header).getCritical());\n            Set<String> supportedCrit = this.critical;\n            String b64Id = DefaultJwsHeader.B64.getId();\n            if (!unencodedPayload.isEmpty() && !this.critical.contains(b64Id)) {\n                // The application developer explicitly indicates they're using a B64 payload, so\n                // ensure that the B64 crit header is supported, even if they forgot to configure it on the\n                // parser builder:\n                supportedCrit = new LinkedHashSet<>(Collections.size(this.critical) + 1);\n                supportedCrit.add(DefaultJwsHeader.B64.getId());\n                supportedCrit.addAll(this.critical);","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L403-L439","documentation":"An unsecured JWS (alg='none') may not use the 'crit' (critical) header parameter, since per RFC 7515 Section 4.1.11 crit must occur only within the JWS Protected Header, which is integrity protected — impossible without a signature. jjwt throws MalformedJwtException when an unsecured JWS header contains a 'crit' entry.","triggerScenarios":"Parsing an alg='none' JWS (with unsecured parsing enabled) whose protected header contains a non-empty 'crit' set.","commonSituations":"Custom token builders that copy full header maps (including crit) between signed and unsecured tokens; extension frameworks attaching crit headers generically regardless of algorithm; hand-crafted tokens during testing.","solutions":["Remove the 'crit' header parameter from unsecured tokens, or sign the token with a real algorithm if crit extensions are needed.","Fix the token producer so crit is only emitted on signed/encrypted JWS/JWEs.","If the extension requires crit integrity protection, switch to a signing algorithm such as ES256 or RS256.","Reject such tokens at ingestion if unsecured extensions are not part of your protocol."],"exampleFix":"// before: unsecured token with crit header\nheader = {\"alg\":\"none\",\"crit\":[\"exp\"],\"exp\":...};\n\n// after: drop crit or sign the token\nheader = {\"alg\":\"none\"}; // or sign with Jwts.SIG.ES256 and keep crit","handlingStrategy":"validation","validationCode":"String headerJson = new String(java.util.Base64.getUrlDecoder().decode(token.split(\"\\\\.\")[0]), java.nio.charset.StandardCharsets.UTF_8);\nif (headerJson.contains(\"alg\\\":\\\"none\\\"\") && headerJson.contains(\"crit\")) throw new IllegalArgumentException(\"unsecured JWS may not use crit\");","typeGuard":null,"tryCatchPattern":"try { return parser.parse(token); }\ncatch (io.jsonwebtoken.MalformedJwtException e) { throw new InvalidTokenException(\"crit on unsecured JWS\", e); }","preventionTips":["Only emit crit on integrity-protected (signed/encrypted) tokens","Copy header maps carefully when converting between token types","Keep extension logic algorithm-aware","Prefer signing over unsecured tokens when using extensions"],"tags":["jwt","jws","unsecured","crit-header","malformed-token"],"backgroundTag":"invalid-argument-value","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}