Why this matters
The bug. The jwt-decode library does what its name says: decode. It does not verify. An attacker forges a JWT with header.payload.<anything>, drops the signature, and your server happily extracts role: "admin" from the payload — because nothing checks that the signature came from your private key.
The fix. Use jsonwebtoken.verify (or jose's jwtVerify) with the secret/public key. These throw on tampered tokens, expired tokens, and tokens signed with the wrong algorithm.
Pattern. Decoder libraries are for the browser, where you genuinely cannot verify (no secret). Server-side, never trust a decoder result.
Review heuristic
Every endpoint that updates a user-owned object needs an explicit allowlist of fields it accepts. Object.assign and equivalents on raw request bodies are the smoking gun.
External reference: CWE-269: Improper Privilege Management.
↳ Real-world JWT bypass class; CWE-347.