Skip to content

CWE-614: Sensitive Cookie Without 'Secure' Flag - Python

Overview

Sensitive Cookie Without 'Secure' Flag in Python web applications occurs when cookies containing sensitive data (session IDs, authentication tokens, user identifiers) are set without the Secure flag. This allows cookies to be transmitted over unencrypted HTTP connections, exposing them to interception attacks such as man-in-the-middle (MITM) attacks, network sniffing, and session hijacking.

Common Python Vulnerability Scenarios:

  • Setting session cookies without secure=True in Flask
  • Django session cookies without SESSION_COOKIE_SECURE = True
  • FastAPI cookies missing secure parameter
  • Custom authentication cookies without proper flags
  • Remember-me cookies transmitted over HTTP
  • OAuth state cookies without secure flag

Python Framework Cookie Security:

  • Flask: response.set_cookie(secure=True, httponly=True, samesite='Strict')
  • Django: SESSION_COOKIE_SECURE = True in settings
  • FastAPI: response.set_cookie(secure=True, httponly=True, samesite='strict')
  • Bottle: response.set_cookie(secure=True, httponly=True)

Primary Defence: Set secure=True, httponly=True, and samesite='Strict' on all cookies containing sensitive data, and enable SESSION_COOKIE_SECURE in production.

Common Vulnerable Patterns

# VULNERABLE - Session cookie without Secure flag
from flask import Flask, request, make_response
import secrets

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')

    if authenticate_user(username, password):
        session_token = secrets.token_hex(32)

        response = make_response({'status': 'logged_in'})

        # VULNERABLE - Missing secure=True
        response.set_cookie(
            'session_id',
            session_token,
            httponly=True,
            max_age=3600
        )

        return response

    return {'error': 'Invalid credentials'}, 401

def authenticate_user(username, password):
    # Authentication logic
    return True

Why this is vulnerable:

  • Cookie transmitted over HTTP
  • Susceptible to MITM attacks
  • Network sniffing can capture session token
  • No protection over insecure connections
settings.py
# VULNERABLE - SESSION_COOKIE_SECURE not set to True
DEBUG = False
ALLOWED_HOSTS = ['example.com']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
]

# VULNERABLE - These should be True in production
SESSION_COOKIE_SECURE = False  # BAD!
CSRF_COOKIE_SECURE = False  # BAD!
SESSION_COOKIE_HTTPONLY = True  # Good, but not enough
views.py
from django.contrib.auth import login
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods

@require_http_methods(["POST"])
def user_login(request):
    username = request.POST.get('username')
    password = request.POST.get('password')

    user = authenticate(request, username=username, password=password)

    if user is not None:
        # VULNERABLE - Session cookie sent without Secure flag
        login(request, user)
        return JsonResponse({'status': 'logged_in'})

    return JsonResponse({'error': 'Invalid credentials'}, status=401)

Why this is vulnerable:

  • SESSION_COOKIE_SECURE = False allows HTTP transmission
  • CSRF token also vulnerable
  • Django sessions exposed to interception
  • Production misconfiguration
# VULNERABLE - FastAPI custom authentication without secure cookies
from fastapi import FastAPI, Response, Request, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
import secrets
from datetime import datetime, timedelta

app = FastAPI()

# In-memory session store (demo purposes)
sessions = {}

class LoginRequest(BaseModel):
    username: str
    password: str

@app.post("/login")
async def login(request: LoginRequest, response: Response):
    if authenticate_user(request.username, request.password):
        session_token = secrets.token_urlsafe(32)

        # Store session
        sessions[session_token] = {
            'username': request.username,
            'created_at': datetime.now()
        }

        # VULNERABLE - Missing secure=True
        response.set_cookie(
            key="session_token",
            value=session_token,
            httponly=True,
            max_age=1800,
            samesite="lax"
        )

        return {"status": "logged_in"}

    raise HTTPException(status_code=401, detail="Invalid credentials")

def authenticate_user(username: str, password: str) -> bool:
    # Authentication logic
    return True

Why this is vulnerable:

  • secure parameter not set
  • Cookie sent over HTTP
  • Session token exposed to network attacks
  • Missing critical security flag
# VULNERABLE - Remember-me functionality with insecure cookies
from flask import Flask, request, make_response
import secrets
import hashlib
from datetime import datetime, timedelta

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login_with_remember():
    username = request.form.get('username')
    password = request.form.get('password')
    remember_me = request.form.get('remember_me') == 'true'

    if authenticate_user(username, password):
        session_token = secrets.token_hex(32)

        response = make_response({'status': 'logged_in'})

        # Session cookie (also vulnerable, but short-lived)
        response.set_cookie(
            'session_id',
            session_token,
            httponly=True,
            max_age=3600
        )

        if remember_me:
            # VULNERABLE - Long-lived remember-me cookie without Secure flag
            remember_token = secrets.token_hex(64)

            # Store token in database
            store_remember_token(username, remember_token)

            response.set_cookie(
                'remember_me',
                remember_token,
                httponly=True,
                max_age=30*24*3600  # 30 days - VERY vulnerable!
            )

        return response

    return {'error': 'Invalid credentials'}, 401

def store_remember_token(username, token):
    # Database storage
    pass

def authenticate_user(username, password):
    return True

Why this is vulnerable:

  • Long-lived cookies especially dangerous
  • 30-day exposure window
  • No secure flag = persistent vulnerability
  • Enables long-term session hijacking
# VULNERABLE - Custom JWT cookie without proper security
from flask import Flask, request, make_response
import jwt
from datetime import datetime, timedelta

app = Flask(__name__)
SECRET_KEY = 'your-secret-key'

@app.route('/api/login', methods=['POST'])
def api_login():
    username = request.json.get('username')
    password = request.json.get('password')

    if authenticate_user(username, password):
        # Create JWT token
        payload = {
            'username': username,
            'exp': datetime.utcnow() + timedelta(hours=1)
        }

        token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')

        response = make_response({'status': 'success'})

        # VULNERABLE - Multiple issues
        response.set_cookie(
            'auth_token',
            token,
            max_age=3600
            # Missing: secure=True
            # Missing: httponly=True
            # Missing: samesite attribute
        )

        return response

    return {'error': 'Authentication failed'}, 401

def authenticate_user(username, password):
    return True

Why this is vulnerable:

  • No secure=True flag
  • No httponly=True (XSS vulnerable)
  • No samesite attribute (CSRF vulnerable)
  • Triple vulnerability in one cookie
# VULNERABLE - OAuth state cookie without security flags
from flask import Flask, request, redirect, make_response
import secrets

app = Flask(__name__)

@app.route('/oauth/authorize')
def oauth_authorize():
    # Generate CSRF protection state
    state = secrets.token_urlsafe(32)

    # VULNERABLE - OAuth state cookie without Secure flag
    response = make_response(redirect(
        f'https://oauth.provider.com/authorize?'
        f'client_id=YOUR_CLIENT_ID&'
        f'redirect_uri=https://example.com/oauth/callback&'
        f'state={state}'
    ))

    response.set_cookie(
        'oauth_state',
        state,
        max_age=600  # 10 minutes
        # Missing: secure=True, httponly=True, samesite
    )

    return response

@app.route('/oauth/callback')
def oauth_callback():
    state_param = request.args.get('state')
    state_cookie = request.cookies.get('oauth_state')

    if state_param != state_cookie:
        return {'error': 'Invalid state'}, 400

    # Continue OAuth flow
    return {'status': 'success'}

Why this is vulnerable:

  • OAuth state token exposed over HTTP
  • CSRF protection compromised
  • Enables OAuth token theft
  • OAuth security model broken

Bottle Framework Without Secure Cookies

# VULNERABLE - Bottle application with insecure cookies
from bottle import Bottle, request, response
import secrets

app = Bottle()

@app.post('/login')
def login():
    username = request.forms.get('username')
    password = request.forms.get('password')

    if authenticate_user(username, password):
        session_id = secrets.token_hex(32)

        # VULNERABLE - Bottle cookie without secure flag
        response.set_cookie(
            'session_id',
            session_id,
            max_age=3600,
            httponly=True
            # Missing: secure=True
        )

        return {'status': 'logged_in'}

    return {'error': 'Invalid credentials'}

def authenticate_user(username, password):
    return True

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

Why this is vulnerable:

  • Bottle framework requires explicit secure=True
  • Cookie transmitted over HTTP
  • Session hijacking possible
  • Framework default is insecure

Pyramid Framework Without Secure Cookies

# VULNERABLE - Pyramid session without secure cookies
from pyramid.config import Configurator
from pyramid.view import view_config
from pyramid.response import Response
import secrets

@view_config(route_name='login', request_method='POST', renderer='json')
def login_view(request):
    username = request.POST.get('username')
    password = request.POST.get('password')

    if authenticate_user(username, password):
        session_token = secrets.token_hex(32)

        # VULNERABLE - Pyramid cookie without secure flag
        response = Response(json_body={'status': 'logged_in'})
        response.set_cookie(
            'session_id',
            session_token,
            max_age=3600,
            httponly=True
            # Missing: secure=True
        )

        return response

    return Response(json_body={'error': 'Invalid credentials'}, status=401)

def authenticate_user(username, password):
    return True

def main(global_config, **settings):
    config = Configurator(settings=settings)
    config.add_route('login', '/login')
    config.scan()
    return config.make_wsgi_app()

Why this is vulnerable:

  • Pyramid sessions exposed
  • No secure flag protection
  • Production deployment risk
  • Framework misconfiguration

Secure Patterns

# SECURE - Flask cookie with proper security flags
from flask import Flask, request, make_response
import secrets
from datetime import timedelta

app = Flask(__name__)

# SECURE - Configure session cookie security
app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Strict',
    PERMANENT_SESSION_LIFETIME=timedelta(hours=1)
)

@app.route('/login', methods=['POST'])
def secure_login():
    username = request.form.get('username')
    password = request.form.get('password')

    if authenticate_user(username, password):
        session_token = secrets.token_hex(32)

        response = make_response({'status': 'logged_in'})

        # SECURE - All critical security flags set
        response.set_cookie(
            'session_id',
            session_token,
            secure=True,        # Only sent over HTTPS
            httponly=True,      # Not accessible via JavaScript
            samesite='Strict',  # CSRF protection
            max_age=3600        # 1 hour expiration
        )

        return response

    return {'error': 'Invalid credentials'}, 401

def authenticate_user(username, password):
    # Secure authentication logic
    return True

if __name__ == '__main__':
    # SECURE - Only run on HTTPS in production
    # Use a proper WSGI server (gunicorn, uWSGI) with TLS
    app.run(ssl_context='adhoc')  # For development only

Why this works:

  • Secure/HttpOnly/SameSite enforce HTTPS-only cookies and block XSS/CSRF.
  • App-wide config applies flags consistently to all session cookies.
  • Short lifetimes and strong tokens limit exposure.
# settings.py - SECURE configuration

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['example.com', 'www.example.com']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
]

# SECURE - Session cookie security settings
SESSION_COOKIE_SECURE = True        # Only send over HTTPS
SESSION_COOKIE_HTTPONLY = True      # Not accessible via JavaScript
SESSION_COOKIE_SAMESITE = 'Strict'  # CSRF protection
SESSION_COOKIE_AGE = 3600           # 1 hour

# SECURE - CSRF cookie security
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Strict'

# SECURE - Additional security settings
SECURE_SSL_REDIRECT = True          # Redirect HTTP to HTTPS
SECURE_HSTS_SECONDS = 31536000      # HTTP Strict Transport Security
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True

# views.py
from django.contrib.auth import authenticate, login
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import ensure_csrf_cookie

@require_http_methods(["POST"])
def secure_login(request):
    username = request.POST.get('username')
    password = request.POST.get('password')

    user = authenticate(request, username=username, password=password)

    if user is not None:
        # SECURE - Django automatically applies SESSION_COOKIE_SECURE
        login(request, user)
        return JsonResponse({'status': 'logged_in'})

    return JsonResponse({'error': 'Invalid credentials'}, status=401)

@ensure_csrf_cookie
def get_csrf_token(request):
    # SECURE - CSRF token sent with secure flag
    return JsonResponse({'csrfToken': 'set_in_cookie'})

Why this works:

  • App-wide settings enforce Secure/HttpOnly/SameSite on session and CSRF cookies.
  • HTTPS redirect + HSTS prevent downgrade and plaintext transport.
  • Short session age limits exposure.

FastAPI With Secure Cookies

# SECURE - FastAPI with proper cookie security
from fastapi import FastAPI, Response, Request, HTTPException, Depends
from fastapi.responses import JSONResponse
from fastapi.security import HTTPBearer
from pydantic import BaseModel
import secrets
from datetime import datetime, timedelta
from typing import Optional

app = FastAPI()

# In-memory session store (use Redis in production)
sessions = {}

class LoginRequest(BaseModel):
    username: str
    password: str

security = HTTPBearer()

def get_current_user(request: Request):
    """Dependency to validate session"""
    session_token = request.cookies.get("session_token")

    if not session_token or session_token not in sessions:
        raise HTTPException(status_code=401, detail="Not authenticated")

    session = sessions[session_token]

    # Check expiration
    if datetime.now() > session['expires_at']:
        del sessions[session_token]
        raise HTTPException(status_code=401, detail="Session expired")

    return session['username']

@app.post("/login")
async def secure_login(request: LoginRequest, response: Response):
    if authenticate_user(request.username, request.password):
        session_token = secrets.token_urlsafe(32)

        # Store session with expiration
        sessions[session_token] = {
            'username': request.username,
            'created_at': datetime.now(),
            'expires_at': datetime.now() + timedelta(hours=1)
        }

        # SECURE - All security flags set
        response.set_cookie(
            key="session_token",
            value=session_token,
            secure=True,        # HTTPS only
            httponly=True,      # Not accessible via JavaScript
            samesite="strict",  # CSRF protection
            max_age=3600        # 1 hour
        )

        return {"status": "logged_in"}

    raise HTTPException(status_code=401, detail="Invalid credentials")

@app.post("/logout")
async def logout(request: Request, response: Response):
    session_token = request.cookies.get("session_token")

    if session_token and session_token in sessions:
        del sessions[session_token]

    # Delete cookie
    response.delete_cookie(
        key="session_token",
        secure=True,
        httponly=True,
        samesite="strict"
    )

    return {"status": "logged_out"}

@app.get("/protected")
async def protected_route(username: str = Depends(get_current_user)):
    return {"message": f"Hello {username}", "protected": True}

def authenticate_user(username: str, password: str) -> bool:
    # Secure authentication logic
    return True

if __name__ == "__main__":
    import uvicorn
    # SECURE - Run with TLS in production
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=8443,
        ssl_keyfile="path/to/key.pem",
        ssl_certfile="path/to/cert.pem"
    )

Why this works:

  • Secure/HttpOnly/SameSite enforce HTTPS-only cookies and block XSS/CSRF.
  • Expiration checks and logout cleanup invalidate stolen tokens quickly.
  • TLS config + strong tokens reduce interception and guessing risk.

Secure Remember-Me Implementation

# SECURE - Remember-me with proper security
from flask import Flask, request, make_response
import secrets
import hashlib
from datetime import datetime, timedelta
import os

app = Flask(__name__)

# SECURE - App configuration
app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Strict',
    REMEMBER_COOKIE_SECURE=True,
    REMEMBER_COOKIE_HTTPONLY=True,
    REMEMBER_COOKIE_DURATION=timedelta(days=30)
)

class RememberMeToken:
    """Secure remember-me token management"""

    @staticmethod
    def generate_token():
        """Generate cryptographically secure token"""
        return secrets.token_urlsafe(64)

    @staticmethod
    def hash_token(token):
        """Hash token for storage"""
        return hashlib.sha256(token.encode()).hexdigest()

    @staticmethod
    def store_token(username, token):
        """Store hashed token in database"""
        token_hash = RememberMeToken.hash_token(token)

        # Store in database with expiration
        db.remember_tokens.insert({
            'username': username,
            'token_hash': token_hash,
            'created_at': datetime.now(),
            'expires_at': datetime.now() + timedelta(days=30)
        })

    @staticmethod
    def verify_token(token):
        """Verify remember-me token"""
        token_hash = RememberMeToken.hash_token(token)

        token_record = db.remember_tokens.find_one({
            'token_hash': token_hash,
            'expires_at': {'$gt': datetime.now()}
        })

        if token_record:
            return token_record['username']

        return None

@app.route('/login', methods=['POST'])
def login_with_remember():
    username = request.form.get('username')
    password = request.form.get('password')
    remember_me = request.form.get('remember_me') == 'true'

    if authenticate_user(username, password):
        session_token = secrets.token_hex(32)

        response = make_response({'status': 'logged_in'})

        # SECURE - Session cookie with all flags
        response.set_cookie(
            'session_id',
            session_token,
            secure=True,
            httponly=True,
            samesite='Strict',
            max_age=3600
        )

        if remember_me:
            remember_token = RememberMeToken.generate_token()
            RememberMeToken.store_token(username, remember_token)

            # SECURE - Remember-me cookie with all flags
            response.set_cookie(
                'remember_me',
                remember_token,
                secure=True,      # HTTPS only
                httponly=True,    # Not accessible via JavaScript
                samesite='Strict', # CSRF protection
                max_age=30*24*3600 # 30 days
            )

        return response

    return {'error': 'Invalid credentials'}, 401

@app.route('/auto-login', methods=['POST'])
def auto_login():
    """Auto-login using remember-me token"""
    remember_token = request.cookies.get('remember_me')

    if not remember_token:
        return {'error': 'No remember-me token'}, 401

    username = RememberMeToken.verify_token(remember_token)

    if username:
        session_token = secrets.token_hex(32)

        response = make_response({'status': 'auto_logged_in', 'username': username})

        # SECURE - Create new session
        response.set_cookie(
            'session_id',
            session_token,
            secure=True,
            httponly=True,
            samesite='Strict',
            max_age=3600
        )

        return response

    return {'error': 'Invalid token'}, 401

def authenticate_user(username, password):
    return True

# Mock database
class MockDB:
    def __init__(self):
        self.remember_tokens = MockCollection()

class MockCollection:
    def __init__(self):
        self.data = []

    def insert(self, doc):
        self.data.append(doc)

    def find_one(self, query):
        # Simple mock implementation
        return None

db = MockDB()

Why this works:

  • Secure/HttpOnly/SameSite protect both session and remember-me cookies.
  • Tokens are hashed at rest and expire, limiting replay and DB compromise impact.
  • Auto-login issues a fresh short-lived session cookie.
# SECURE - JWT in cookie with all security flags
from flask import Flask, request, make_response
import jwt
from datetime import datetime, timedelta
import os

app = Flask(__name__)

# SECURE - Use environment variable for secret
JWT_SECRET = os.environ.get('JWT_SECRET_KEY')
if not JWT_SECRET:
    raise ValueError("JWT_SECRET_KEY environment variable not set")

@app.route('/api/login', methods=['POST'])
def secure_api_login():
    username = request.json.get('username')
    password = request.json.get('password')

    if authenticate_user(username, password):
        # Create JWT with expiration
        payload = {
            'username': username,
            'iat': datetime.utcnow(),
            'exp': datetime.utcnow() + timedelta(hours=1)
        }

        token = jwt.encode(payload, JWT_SECRET, algorithm='HS256')

        response = make_response({'status': 'success'})

        # SECURE - All security flags set
        response.set_cookie(
            'auth_token',
            token,
            secure=True,        # HTTPS only
            httponly=True,      # Not accessible via JavaScript
            samesite='Strict',  # CSRF protection
            max_age=3600        # 1 hour
        )

        return response

    return {'error': 'Authentication failed'}, 401

@app.route('/api/protected', methods=['GET'])
def protected_api():
    auth_token = request.cookies.get('auth_token')

    if not auth_token:
        return {'error': 'Not authenticated'}, 401

    try:
        # Verify JWT
        payload = jwt.decode(
            auth_token,
            JWT_SECRET,
            algorithms=['HS256']
        )

        return {
            'message': f'Hello {payload["username"]}',
            'protected': True
        }
    except jwt.ExpiredSignatureError:
        return {'error': 'Token expired'}, 401
    except jwt.InvalidTokenError:
        return {'error': 'Invalid token'}, 401

def authenticate_user(username, password):
    return True

Why this works:

  • Secure/HttpOnly/SameSite cookies protect JWTs from XSS/CSRF and HTTP leakage.
  • Expiration is enforced by both cookie max-age and JWT exp.
  • Secret management via env vars prevents hardcoded secrets.
# SECURE - OAuth state cookie with proper security
from flask import Flask, request, redirect, make_response, session
import secrets
import os

app = Flask(__name__)
app.secret_key = os.environ.get('FLASK_SECRET_KEY')

# SECURE - Configure session security
app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax'  # Lax for OAuth redirects
)

OAUTH_CLIENT_ID = os.environ.get('OAUTH_CLIENT_ID')
OAUTH_CLIENT_SECRET = os.environ.get('OAUTH_CLIENT_SECRET')

@app.route('/oauth/authorize')
def oauth_authorize():
    # Generate CSRF protection state
    state = secrets.token_urlsafe(32)

    # Store state in session (automatically uses secure cookies)
    session['oauth_state'] = state
    session['oauth_initiated_at'] = datetime.now().isoformat()

    # Build OAuth URL
    oauth_url = (
        f'https://oauth.provider.com/authorize?'
        f'client_id={OAUTH_CLIENT_ID}&'
        f'redirect_uri=https://example.com/oauth/callback&'
        f'response_type=code&'
        f'state={state}&'
        f'scope=read:user'
    )

    return redirect(oauth_url)

@app.route('/oauth/callback')
def oauth_callback():
    state_param = request.args.get('state')
    state_session = session.get('oauth_state')
    initiated_at = session.get('oauth_initiated_at')

    # Verify state parameter
    if not state_param or state_param != state_session:
        return {'error': 'Invalid state parameter'}, 400

    # Check state age (prevent replay)
    if initiated_at:
        initiated_time = datetime.fromisoformat(initiated_at)
        if datetime.now() - initiated_time > timedelta(minutes=10):
            return {'error': 'State expired'}, 400

    # Clear state from session
    session.pop('oauth_state', None)
    session.pop('oauth_initiated_at', None)

    # Exchange code for token
    code = request.args.get('code')

    # Continue OAuth flow...
    return {'status': 'success'}

from datetime import datetime, timedelta

Why this works:

  • OAuth state is stored in a secure session cookie (Lax for redirects).
  • State validation + short expiration block CSRF and replay.
  • Single-use cleanup and strong state tokens reduce abuse.

Verification

After implementing the recommended secure patterns, verify the fix through multiple approaches:

  • Manual testing: Submit malicious payloads relevant to this vulnerability and confirm they're handled safely without executing unintended operations
  • Code review: Confirm all instances use the secure pattern (parameterized queries, safe APIs, proper encoding) with no string concatenation or unsafe operations
  • Static analysis: Use security scanners to verify no new vulnerabilities exist and the original finding is resolved
  • Regression testing: Ensure legitimate user inputs and application workflows continue to function correctly
  • Edge case validation: Test with special characters, boundary conditions, and unusual inputs to verify proper handling
  • Framework verification: If using a framework or library, confirm the recommended APIs are used correctly according to documentation
  • Authentication/session testing: Verify security controls remain effective and cannot be bypassed (if applicable to the vulnerability type)
  • Rescan: Run the security scanner again to confirm the finding is resolved and no new issues were introduced

Additional Resources