Absolute timeout max 8 hours regardless of activity
Why it matters
An inactivity timeout alone is insufficient if a sufficiently active user — or an attacker who has hijacked a session and keeps it alive with synthetic requests — can maintain access indefinitely. CWE-613 and PCI-DSS 4.0 Req 8.2.8 require an absolute wall-clock limit on session lifetime regardless of ongoing activity. Without an absolute cap, a compromised session token issued at 9 AM remains valid at 11 PM of the same day. NIST 800-63B (AC-12) explicitly calls for session termination after a maximum duration. The 8-hour ceiling corresponds to a full working day — sessions that outlast the workday create overnight exposure with no legitimate justification for financial applications.
Severity rationale
High because an indefinitely active session allows a hijacked or stolen token to remain valid for days, enabling prolonged unauthorized access to financial operations that an inactivity timeout alone cannot prevent.
Remediation
Add a maxSessionAge distinct from maxAge in src/lib/session.ts or src/middleware.ts. The absolute cap must be 28800 seconds (8 hours) regardless of user activity:
session({
store: redisStore(),
cookie: {
maxAge: 8 * 60 * 60 * 1000, // 8-hour absolute ceiling
httpOnly: true,
secure: true,
sameSite: 'Strict'
},
maxSessionAge: 8 * 60 * 60 * 1000
})
For NextAuth JWT, enforce the absolute limit inside the jwt callback:
callbacks: {
jwt: ({ token }) => {
if (!token.iat) token.iat = Math.floor(Date.now() / 1000);
if (Math.floor(Date.now() / 1000) - token.iat > 8 * 60 * 60) return null;
return token;
}
}
Detection
- ID:
absolute-timeout-8hrs - Severity:
high - What to look for: Count all session configuration settings and look for an absolute timeout distinct from inactivity timeout. Quote the actual absolute timeout value found (in hours or seconds). Verify the absolute timeout is no more than 28800 seconds (8 hours). An absolute timeout exceeding 8 hours does not count as pass.
- Pass criteria: An absolute timeout is configured to no more than 28800 seconds (8 hours), regardless of user activity. Report the count even on pass (e.g., "Absolute timeout: 28800s (8 hours) via maxSessionAge in session config"). Quote the actual setting found.
- Fail criteria: No absolute timeout configured (0 settings found), or absolute timeout exceeds 28800 seconds (8 hours), or timeout only applies as inactivity (no absolute max).
- Skip (N/A) when: The application is API-only or does not require financial operations — cite the actual project type found.
- Detail on fail:
"No absolute session timeout — 0 absolute timeout settings found. Sessions persist indefinitely while active."or"Absolute timeout is 86400s (24 hours) — exceeds 28800s (8 hour) maximum" - Cross-reference: Check
finserv-session-security.session-lifecycle.inactivity-timeout-15minfor inactivity timeout. - Remediation: Add an absolute session timeout in your session middleware or JWT logic (in
src/lib/session.tsorsrc/middleware.ts):For next-auth with JWT:session({ store: redisStore(), cookie: { maxAge: 8 * 60 * 60 * 1000, // 8 hours absolute httpOnly: true, secure: true, sameSite: 'Strict' }, maxSessionAge: 8 * 60 * 60 * 1000 })callbacks: { jwt: ({ token, isNewUser }) => { if (isNewUser || !token.iat) { token.iat = Math.floor(Date.now() / 1000); } const sessionMaxAge = 8 * 60 * 60; // 8 hours in seconds if (Math.floor(Date.now() / 1000) - token.iat > sessionMaxAge) { return null; // Token expired } return token; } }
External references
- cwe · CWE-613 — Insufficient Session Expiration
- owasp:2021 · A07
- pci-dss:4.0 · Req 8.2.8
- nist:rev5 · AC-12
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-session-security·automated