Configuration & Environment
MCP server issues JWTs without an `exp` claim — any token, once leaked, is valid forever, eliminating revocation as a defense.
The `exp` claim is the JWT spec's expiration mechanism. Without it, a leaked token is permanently valid and there's no graceful rotation story — the only recovery is rotating the signing key, which invalidates every issued token at once. Short-lived tokens (15-30 minutes) limit the blast radius of any single leak.
Long-lived MCP server sessions encourage developers to issue long-lived tokens for ergonomic reasons. The cost is reversed when a token leaks: instead of a 30-minute exposure window, it's an indefinite one. Combined with token-passthrough patterns (MCP-265), a single leaked MCP-server token can be replayed to multiple downstream APIs forever.
import jwt |
def issue_token(user_id: str) -> str: |
payload = {"sub": user_id, "scope": "read"} |
return jwt.encode(payload, KEY, algorithm="RS256") |
import jwt |
from datetime import datetime, timedelta, timezone |
def issue_token(user_id: str) -> str: |
now = datetime.now(timezone.utc) |
payload = { |
"sub": user_id, |
"scope": "read", |
"iat": now, |
"exp": now + timedelta(minutes=15), |
} |
return jwt.encode(payload, KEY, algorithm="RS256") |
MCPSafe flags `jwt.encode(...)` / `jsonwebtoken.sign(...)` calls whose payload object lacks an `exp` field. Calls that pass `expiresIn:` (jsonwebtoken) or include `exp` in the payload dict are exempted.
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now