Weakness reference
CWE-613

Insufficient Session Expiration

Session expiration is the mechanism that automatically logs out a user after a period of inactivity or elapsed time. When this is not properly implemented, an…

01Summary

Session expiration is the mechanism that automatically logs out a user after a period of inactivity or elapsed time. When this is not properly implemented, an attacker who gains access to an unattended device or intercepts a session token can impersonate the user indefinitely. This is a common vulnerability in web applications and is particularly dangerous for high-value accounts or sensitive operations.

02How It Happens

Sessions are typically managed via cookies or tokens that identify a logged-in user. The application must track when a session was created or last used, and invalidate it after a configurable timeout. If the application fails to enforce this expiration—either by not checking the timestamp at all, by setting the timeout too long, or by allowing the session to be renewed indefinitely without re-authentication—an attacker with access to a valid session token can use it to perform actions as that user. This is especially risky in shared or public environments where a user may step away from an unlocked device.

03Real-World Impact

An attacker who obtains a session token from an unattended workstation, a network intercept, or a stolen device can access the user's account and perform any action the user is authorized to perform—changing passwords, transferring funds, modifying data, or escalating privileges. In multi-user environments (libraries, offices, cafes), this can lead to account takeover without the user's knowledge. The longer a session remains valid, the larger the window of opportunity for exploitation.

04Vulnerable & Fixed Patterns

Vulnerable pattern
from flask import Flask, session, request
import time

app = Flask(__name__)
app.secret_key = 'secret'

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    session['username'] = username
    session['login_time'] = time.time()
    return 'Logged in'

@app.route('/dashboard')
def dashboard():
    # No expiration check — session is valid forever
    if 'username' in session:
        return f'Welcome, {session["username"]}'
    return 'Not logged in'

Why it's vulnerable:
The session is created but never checked for age. A session token obtained by an attacker will remain valid indefinitely, even after hours or days of inactivity.

Fixed pattern
from flask import Flask, session, request
import time

app = Flask(__name__)
app.secret_key = 'secret'
SESSION_TIMEOUT = 1800  # 30 minutes in seconds

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    session['username'] = username
    session['login_time'] = time.time()
    session.permanent = True
    app.permanent_session_lifetime = SESSION_TIMEOUT
    return 'Logged in'

@app.route('/dashboard')
def dashboard():
    if 'username' in session:
        elapsed = time.time() - session.get('login_time', 0)
        if elapsed > SESSION_TIMEOUT:
            session.clear()
            return 'Session expired. Please log in again.'
        session['login_time'] = time.time()  # Reset on activity
        return f'Welcome, {session["username"]}'
    return 'Not logged in'
Vulnerable pattern
<?php
session_start();

if ($_POST['username']) {
    $_SESSION['username'] = $_POST['username'];
    $_SESSION['login_time'] = time();
}

if (isset($_SESSION['username'])) {
    echo "Welcome, " . htmlspecialchars($_SESSION['username']);
} else {
    echo "Not logged in";
}
?>

Why it's vulnerable:
The session is created but never validated for timeout. PHP's default session handler may have a long garbage-collection interval, and no explicit expiration check is performed in the application code.

Fixed pattern
<?php
session_start();
define('SESSION_TIMEOUT', 1800);  // 30 minutes

if ($_POST['username']) {
    $_SESSION['username'] = $_POST['username'];
    $_SESSION['login_time'] = time();
}

if (isset($_SESSION['username'])) {
    $elapsed = time() - $_SESSION['login_time'];
    if ($elapsed > SESSION_TIMEOUT) {
        session_destroy();
        echo "Session expired. Please log in again.";
    } else {
        $_SESSION['login_time'] = time();  // Reset on activity
        echo "Welcome, " . htmlspecialchars($_SESSION['username']);
    }
} else {
    echo "Not logged in";
}
?>

05Prevention Checklist

Set a reasonable session timeout (typically 15–30 minutes for sensitive applications, longer for low-risk contexts) and enforce it on every request.
Reset the inactivity timer on each user action, so active sessions are not prematurely expired.
Provide a logout function that explicitly destroys the session and clears all session data.
Use secure, HTTP-only session cookies to prevent client-side tampering.
Implement absolute session limits (e.g., a session expires after 8 hours regardless of activity) for high-security applications.
Log session creation and destruction events for audit and anomaly detection.

06Signs You May Already Be Affected

Check your application logs for sessions that remain active for unusually long periods without corresponding user activity. Review your session configuration to confirm that a timeout value is set and is being enforced on every request. If you find sessions that persist for hours or days, or if users report unauthorized actions on their accounts after stepping away from a device, session expiration may not be working correctly.

07Related Recent Vulnerabilities