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.
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.
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;
}
}
finserv-session-security.session-lifecycle.absolute-timeout-8hrshigh"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"finserv-session-security.session-lifecycle.inactivity-timeout-15min for inactivity timeout.src/lib/session.ts or src/middleware.ts):
session({
store: redisStore(),
cookie: {
maxAge: 8 * 60 * 60 * 1000, // 8 hours absolute
httpOnly: true,
secure: true,
sameSite: 'Strict'
},
maxSessionAge: 8 * 60 * 60 * 1000
})
For next-auth with JWT:
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;
}
}