highCWE-613A07:2021

JWT Without Expiration

JWTs signed without an `exp` claim that never expire, meaning a stolen token grants permanent access with no way to revoke it.

How It Works

JWTs are stateless by design — the server doesn't store them. Expiration (`exp`) is the primary mechanism to limit their lifetime. Without it, a token stolen today is still valid years from now. You can't invalidate it without building a blacklist, which defeats the stateless purpose.

Vulnerable Code
// BAD: no expiration set
const token = jwt.sign(
  { userId: user.id, role: user.role },
  process.env.JWT_SECRET!
);
Secure Code
// GOOD: short expiration + refresh token pattern
const token = jwt.sign(
  { userId: user.id, role: user.role },
  process.env.JWT_SECRET!,
  { expiresIn: '15m' }
);

Real-World Example

A SaaS app issued non-expiring JWTs for API access. When an employee left the company, their token kept working indefinitely because there was no expiry and no revocation mechanism in place.

How to Prevent It

  • Always set expiresIn when signing JWTs — 15 minutes for access tokens, 7 days for refresh tokens
  • Implement a refresh token rotation pattern so short-lived tokens stay usable
  • Store refresh tokens server-side so you can revoke them on logout or breach
  • Use a library like jose or jsonwebtoken that validates exp automatically on verify

Affected Technologies

nodejsNext.jsPython

Data Hogo detects this vulnerability automatically.

Scan Your Repo Free

Related Vulnerabilities