session-fixation-anti-pattern

session-fixation-anti-pattern

Security anti-pattern for session fixation vulnerabilities (CWE-384). Use when generating or reviewing code that handles user sessions, login flows, or authentication state changes. Detects failure to regenerate session IDs after authentication.

2Star
1Fork
更新于 1/22/2026
SKILL.md
readonly只读
name
"session-fixation-anti-pattern"
description

"Security anti-pattern for session fixation vulnerabilities (CWE-384). Use when generating or reviewing code that handles user sessions, login flows, or authentication state changes. Detects failure to regenerate session IDs after authentication."

Session Fixation Anti-Pattern

Severity: High

Summary

Session fixation is a type of session hijacking attack where an attacker "fixes" a user's session ID before the user logs in. The attacker first obtains a valid session ID from the application (e.g., by visiting the login page). Then, they trick the victim into using this pre-determined session ID to log in. Because the application fails to generate a new session ID after successful authentication, the victim becomes logged into the attacker's chosen session. The attacker, still possessing the original session ID, can then hijack the victim's authenticated session.

The Anti-Pattern

The anti-pattern is an application that uses the same session identifier before and after a user authenticates.

BAD Code Example

# VULNERABLE: The session ID is not regenerated after successful login.
from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = 'your_secret_key' # Insecure in production

# Attacker visits this page, gets a session ID, e.g., 'attacker_session_id'.
@app.route('/')
def index():
    if 'username' in session:
        return f'Hello {session["username"]}! <a href="/logout">Logout</a>'
    return 'Welcome, please <a href="/login">Login</a>'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if check_credentials(username, password):
            # CRITICAL FLAW: The session ID is not regenerated here.
            # The existing session, potentially fixed by an attacker, is now authenticated.
            session['username'] = username
            return redirect(url_for('index'))
        return 'Invalid credentials'
    return '''
        <form method="post">
            <p><input type=text name=username></p>
            <p><input type=password name=password></p>
            <p><input type=submit value=Login></p>
        </form>
    '''

# Attacker Scenario:
# 1. Attacker visits `http://vulnerable-app.com/`. The server assigns a session ID, e.g., `session_id=ABCD`.
# 2. Attacker crafts a phishing link: `http://vulnerable-app.com/login?session_id=ABCD`.
#    (Note: Modern browsers prevent injecting session IDs via URL, but other techniques exist, e.g., via referrer, HTTP response splitting, or exploiting XSS).
# 3. Attacker sends the link to the victim.
# 4. Victim clicks the link, their browser uses `session_id=ABCD`.
# 5. Victim logs in. The server authenticates the victim but *reuses* `session_id=ABCD`.
# 6. Attacker, still holding `session_id=ABCD`, now accesses the victim's authenticated session.

GOOD Code Example

# SECURE: Regenerate the session ID after successful login and on privilege changes.
from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = 'your_secret_key' # Use a strong, securely managed key

@app.route('/')
def index_secure():
    if 'username' in session:
        return f'Hello {session["username"]}! <a href="/logout">Logout</a>'
    return 'Welcome, please <a href="/login_secure">Login Securely</a>'

@app.route('/login_secure', methods=['GET', 'POST'])
def login_secure():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if check_credentials(username, password):
            # CRITICAL: Regenerate the session ID after successful authentication.
            # This creates a new session, invalidating any pre-login session ID.
            session.regenerate() # Flask's way to generate a new session ID.
            session['username'] = username
            return redirect(url_for('index_secure'))
        return 'Invalid credentials'
    return '''
        <form method="post">
            <p><input type=text name=username></p>
            <p><input type=password name=password></p>
            <p><input type=submit value=Login></p>
        </form>
    '''

@app.route('/logout')
def logout():
    session.clear() # Invalidate session data.
    session.regenerate() # Regenerate session ID to prevent reuse.
    return redirect(url_for('index_secure'))

Detection

  • Review login flows: Trace the code paths involved in user authentication. Verify that after a successful login, the application explicitly invalidates the old session and generates a completely new session ID.
  • Check session management libraries: Understand how your web framework or session management library handles session ID generation and regeneration. Ensure it's used correctly.
  • Test with a fixed session ID: Manually attempt to set a session ID (e.g., using browser developer tools or a proxy like Burp Suite) before logging in. After logging in, check if the session ID remains the same.

Prevention

  • [ ] Regenerate the session ID after any change in the user's authentication state, especially after a successful login. This creates a new session, effectively invalidating any pre-login session ID an attacker might have fixed.
  • [ ] Regenerate the session ID on privilege level changes (e.g., when a user promotes themselves to administrator).
  • [ ] Invalidate the old session on the server-side when a new session is created.
  • [ ] Ensure session cookies are set with secure flags:
    • HttpOnly: Prevents client-side scripts from accessing the cookie.
    • Secure: Ensures the cookie is only sent over HTTPS.
    • SameSite: Helps prevent CSRF attacks.
  • [ ] Implement session timeouts: Both absolute timeouts and idle timeouts should be used to limit the window of opportunity for an attacker.

Related Security Patterns & Anti-Patterns

References

You Might Also Like

Related Skills

create-pr

create-pr

170Kdev-devops

Creates GitHub pull requests with properly formatted titles that pass the check-pr-title CI validation. Use when creating PRs, submitting changes for review, or when the user says /pr or asks to create a pull request.

n8n-io avatarn8n-io
获取

Guide for performing Chromium version upgrades in the Electron project. Use when working on the roller/chromium/main branch to fix patch conflicts during `e sync --3`. Covers the patch application workflow, conflict resolution, analyzing upstream Chromium changes, and proper commit formatting for patch fixes.

electron avatarelectron
获取
pr-creator

pr-creator

92Kdev-devops

Use this skill when asked to create a pull request (PR). It ensures all PRs follow the repository's established templates and standards.

google-gemini avatargoogle-gemini
获取
clawdhub

clawdhub

87Kdev-devops

Use the ClawdHub CLI to search, install, update, and publish agent skills from clawdhub.com. Use when you need to fetch new skills on the fly, sync installed skills to latest or a specific version, or publish new/updated skill folders with the npm-installed clawdhub CLI.

moltbot avatarmoltbot
获取
tmux

tmux

87Kdev-devops

Remote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.

moltbot avatarmoltbot
获取
create-pull-request

create-pull-request

57Kdev-devops

Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, and PR creation using the gh CLI tool.

cline avatarcline
获取