SecureBlockLog inStart a pentest
Vulnerability Repository
MediumAuthentication

Insufficient Session Expiry

Sessions that persist indefinitely or for excessive durations extend the window for session theft, replay attacks, and unauthorized access from shared or stolen devices.

CVSS 5.3CWE CWE-613OWASP A07:2021 — Identification and Authentication Failures

Description

Insufficient session expiry (CWE-613) occurs when an application issues session tokens or authentication credentials that remain valid for an excessively long time or indefinitely. This vulnerability falls under OWASP A07:2021 (Identification and Authentication Failures) and directly extends the window of opportunity for any attack that requires a valid session token: stolen session cookies, XSS-extracted tokens, shoulder-surfed sessions on shared devices, or captured tokens from network interception.

The problem manifests across three distinct patterns: absolute expiry (sessions that never expire or expire after weeks/months), idle expiry (sessions that remain valid despite extended inactivity), and post-logout validity (sessions that continue to work after the user explicitly logs out). All three represent a failure to limit the lifetime of authentication credentials, amplifying the impact of any credential theft.

In mobile applications, the pattern extends to refresh tokens with multi-year lifetimes, JWTs with distant exp claims, and API keys that are never rotated. In web applications, "remember me" functionality implemented with long-lived permanent cookies rather than secure device registration creates persistent session exposure risks.

How It Works

A penetration tester tests session expiry with the following steps:

Absolute expiry test:

# 1. Log in and capture the session cookie
Cookie: session=eyJhbGciOiJIUzI1NiJ9...

# 2. Wait 7 days

# 3. Use the same cookie
curl -H "Cookie: session=eyJhbGciOiJIUzI1NiJ9..." https://target.com/api/profile
# Response: 200 OK with user data — session still valid after 7 days

Post-logout validity test:

# 1. Log in, capture session token
# 2. Log out via the UI
# 3. Replay the session token
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." https://target.com/api/user
# Response: 200 OK — server-side session not invalidated on logout

This is extremely common with JWT-based authentication. JWTs are stateless — there's no server-side session store to invalidate. If a JWT with a 24-hour exp claim is stolen and the user logs out, the token remains cryptographically valid for the remainder of its lifetime. Applications that rely on JWT expiry alone without a token revocation mechanism have no way to invalidate sessions on demand.

Idle timeout bypass:

# Application sets 30-minute idle timeout
# Attacker's script makes a request every 29 minutes to reset the idle timer
while True:
    requests.get("https://target.com/api/ping", headers={"Cookie": stolen_session})
    time.sleep(1740)  # 29 minutes

A stolen session can be kept alive indefinitely by periodic pings if the application uses only idle timeouts without an absolute maximum lifetime.

Impact

  • Extended Session Hijacking Window — Stolen session tokens (via XSS, network interception, or device theft) remain exploitable for the session's full lifetime
  • Unauthorized Shared-Device Access — Users who access applications from shared computers leave persistent sessions accessible to subsequent users
  • Post-Logout Token Replay — Authentication tokens remain valid after the user logs out, enabling replay attacks against any captured token
  • Persistence After Password Change — Sessions from before a password change remain active if the application doesn't invalidate all sessions on credential change

Detection

  1. Test absolute session lifetime — log in, record the session token, wait 24 hours, and reuse it. Document the maximum lifetime before expiry.
  2. Test post-logout validity — log in, record the token, log out, and immediately replay the token in a direct API request. A 200 response indicates the session was not server-side invalidated.
  3. Test idle timeout — log in, wait 30 minutes without activity, and attempt to use the session. If the application has no idle timeout, the session persists indefinitely.
  4. Decode JWT exp claim — base64-decode the JWT payload and inspect the exp timestamp. Calculate the token lifetime. More than 24 hours for regular sessions or more than 1 hour for sensitive operations is excessive.
  5. Test session persistence after password change — change the account password, then replay a session token captured before the change. The old session should be invalidated.
  6. Test concurrent session limits — log in from multiple browsers simultaneously. Applications should either limit concurrent sessions or provide a "log out all sessions" mechanism.

Remediation

Implement both absolute and idle expiry. Set a hard absolute maximum (e.g., 12 hours for web apps, 24 hours for mobile) and an idle timeout (e.g., 30 minutes for sensitive apps, 2 hours for regular apps). The idle timer should reset on activity, but the absolute timer must not:

// Express.js — session with both timeouts
app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: {
    maxAge: 12 * 60 * 60 * 1000, // 12 hour absolute maximum
    secure: true,
    httpOnly: true,
    sameSite: 'strict'
  },
  rolling: true, // Reset idle timer on activity
  resave: false,
  saveUninitialized: false
}));

Implement server-side session invalidation. For JWT-based systems, maintain a token denylist (Redis works well) or use short-lived access tokens (15 minutes) with separate refresh token rotation:

// On logout — add token JTI to denylist
await redis.setex(`denylist:${decoded.jti}`, decoded.exp - Date.now()/1000, '1');

Invalidate all sessions on password change. When a user changes their password, revoke all other active sessions to limit the impact of credential-based takeover.

Provide session management UI. Allow users to view and revoke active sessions, including location and device information. This is both a security control and a trust-building feature.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping