Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.
Why this matters
An unsecured ("alg=none") token can be forged by anyone. Changing the claims (e.g. the subject or roles) costs nothing because there is no signature to verify. This is a common AI-generated mistake: the "plaintext"/"unsecured" JWT API is reached for during prototyping and never swapped for a signed token.
Sign tokens and verify their signatures. With nimbus-jose-jwt use SignedJWT (and verify with a JWSVerifier); with jjwt build tokens via Jwts.builder()...signWith(key) and parse them with parseSignedClaims (or the legacy parseClaimsJws) instead of parseClaimsJwt / parsePlaintextJwt.
VULNERABLE
vulnerable.java
import com.nimbusds.jwt.JWTClaimsSet;import com.nimbusds.jwt.PlainJWT;import io.jsonwebtoken.Jwts;class UnsignedJwt { // nimbus-jose-jwt: building an unsecured ("alg=none") JWT. PlainJWT nimbusUnsecured(JWTClaimsSet claims) { // ruleid: auth.java.jwt.unsigned-jwt return new PlainJWT(claims); } // jjwt: parsing an unsigned JWT with claims. void jjwtParseClaimsJwt(String token, byte[] key) { // ruleid: auth.java.jwt.unsigned-jwt Jwts.parser().build().parseClaimsJwt(token); } // jjwt: parsing an unsigned plaintext JWT. void jjwtParsePlaintextJwt(String token) { // ruleid: auth.java.jwt.unsigned-jwt Jwts.parser().build().parsePlaintextJwt(token); }}
SAFE
safe.java
import com.nimbusds.jose.JWSAlgorithm;import com.nimbusds.jose.JWSHeader;import com.nimbusds.jose.JWSSigner;import com.nimbusds.jwt.JWTClaimsSet;import com.nimbusds.jwt.SignedJWT;import io.jsonwebtoken.Jwts;import javax.crypto.SecretKey;class SignedJwtOk { // nimbus-jose-jwt: a properly signed JWT. SignedJWT nimbusSigned(JWTClaimsSet claims, JWSSigner signer) throws Exception { // ok: auth.java.jwt.unsigned-jwt SignedJWT jwt = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claims); jwt.sign(signer); return jwt; } // jjwt: build a signed token. String jjwtSign(SecretKey key) { // ok: auth.java.jwt.unsigned-jwt return Jwts.builder().subject("alice").signWith(key).compact(); } // jjwt: parse a signed token, verifying the signature. void jjwtParseSigned(String token, SecretKey key) { // ok: auth.java.jwt.unsigned-jwt Jwts.parser().verifyWith(key).build().parseSignedClaims(token); }}
Suppressing this rule
If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.