Fix guide · critical · jwt_alg_none
JWT in client bundle uses alg=none
A JWT in your client JavaScript declares alg: "none" in its header. Tokens with alg=none are unsigned — anyone reading the token can forge a copy with arbitrary claims, and any backend that accepts alg=none will treat the forgery as valid.
Why it matters
The none algorithm exists in the JWT spec for the case where the surrounding transport guarantees integrity (e.g. tokens stored in a signed envelope). Almost no real backend should accept it, but every JWT library historically had a bug where the algorithm choice came from the token header itself — so an attacker could take a signed token, change the header to none, strip the signature, and the library would accept it. This bug has been re-introduced into multiple libraries multiple times. The defence is rejecting alg=none at the verifier; finding such a token in your bundle suggests your auth flow generates them, which means your verifier accepts them.
How to fix it
The token itself is a symptom — the bug is your verifier. Find the verification code and explicitly reject alg=none:
import { jwtVerify, importSPKI } from "jose";
const key = await importSPKI(process.env.JWT_PUBLIC_KEY!, "RS256");
export async function verify(token: string) {
// Whitelist the exact algorithms you actually use.
// Pin them — never derive from the token header.
const { payload } = await jwtVerify(token, key, {
algorithms: ["RS256"], // explicit list rejects 'none' and HS256-with-pubkey attacks
issuer: "https://your-app.example.com",
audience: "your-app",
});
return payload;
}
If you're using jsonwebtoken (the legacy library), the same shape:
jwt.verify(token, key, { algorithms: ["RS256"] });
After fixing the verifier, mint fresh tokens with a real algorithm (RS256 / EdDSA / HS256 with a strong server-only secret), invalidate all currently-issued tokens, and audit your auth logs for any successful login that used alg=none — those sessions should be terminated.
Full guide: /blog/jwt-mistakes-vibe-coded.
Did vibecheck flag this on your app?
If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.
Run another inspection