Weakness reference
CWE-565

Reliance on Cookies without Validation and Integrity Checking

This weakness occurs when an application stores sensitive data or logic-critical information in cookies without verifying that the cookie hasn't been tampered…

01Summary

This weakness occurs when an application stores sensitive data or logic-critical information in cookies without verifying that the cookie hasn't been tampered with. Because cookies are stored on the client side, an attacker can easily modify them using browser developer tools or automated scripts. If the application trusts the cookie value without validation, the attacker can manipulate application behavior, bypass access controls, or escalate privileges.

02How It Happens

Cookies are convenient for storing session identifiers, user preferences, and other state information, but they are inherently untrusted because they live on the client's machine. When a developer stores a value in a cookie (such as a user role, discount flag, or authentication token) and later reads it back without cryptographic verification, they assume the cookie hasn't been modified. An attacker can intercept the HTTP response, edit the cookie in their browser, and send it back to the server. If the server accepts the modified cookie at face value, the attacker's forged data influences the application's decision-making.

The root cause is the absence of integrity checking—typically a cryptographic signature or HMAC—that would prove the cookie came from the server and hasn't been altered since it was issued.

03Real-World Impact

An attacker can escalate their privileges by changing a role cookie from user to admin, bypass payment or discount logic by modifying a price or coupon flag, or forge session state to impersonate another user. In some cases, modified cookies can trigger unintended code paths, leading to information disclosure, unauthorized actions, or account takeover. The impact depends on what data the application stores in the cookie and how much it relies on that data for security decisions.

04Vulnerable & Fixed Patterns

Vulnerable pattern
from flask import Flask, request, make_response

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    
    # Assume password is verified correctly
    if verify_password(username, password):
        response = make_response("Login successful")
        response.set_cookie('user_role', 'admin')  # Stores role in plain cookie
        return response

@app.route('/admin')
def admin_panel():
    user_role = request.cookies.get('user_role')
    if user_role == 'admin':  # Trusts cookie without verification
        return "Admin panel content"
    return "Access denied", 403

Why it's vulnerable:
The user_role cookie is set by the server but never signed or verified. An attacker can open their browser's developer tools, change the cookie value to admin, and gain access to the admin panel without authentication.

Fixed pattern
from flask import Flask, request, make_response
from itsdangerous import URLSafeTimedSerializer

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    
    if verify_password(username, password):
        response = make_response("Login successful")
        # Sign the role data with a secret key
        signed_role = serializer.dumps({'role': 'admin', 'user': username})
        response.set_cookie('user_role', signed_role, httponly=True, secure=True)
        return response

@app.route('/admin')
def admin_panel():
    signed_role = request.cookies.get('user_role')
    try:
        # Verify and deserialize the signed cookie
        data = serializer.loads(signed_role, max_age=3600)
        if data.get('role') == 'admin':
            return "Admin panel content"
    except:
        pass
    return "Access denied", 403
Vulnerable pattern
<?php
// User logs in
if (verify_password($_POST['username'], $_POST['password'])) {
    // Store user role in a plain cookie
    setcookie('user_role', 'admin', time() + 3600);
    echo "Login successful";
}

// Later, check if user is admin
if ($_COOKIE['user_role'] === 'admin') {
    echo "Admin panel content";
} else {
    http_response_code(403);
    echo "Access denied";
}
?>

Why it's vulnerable:
The user_role cookie is set without any signature or integrity check. An attacker can modify the cookie in their browser to admin and bypass the access control check.

Fixed pattern
<?php
// User logs in
if (verify_password($_POST['username'], $_POST['password'])) {
    $username = $_POST['username'];
    $role = 'admin';
    
    // Create a signed cookie using HMAC
    $secret = 'your-secret-key-here';
    $data = json_encode(['user' => $username, 'role' => $role]);
    $signature = hash_hmac('sha256', $data, $secret);
    $signed_cookie = base64_encode($data) . '.' . $signature;
    
    setcookie('user_role', $signed_cookie, time() + 3600, '/', '', true, true);
    echo "Login successful";
}

// Later, verify the signed cookie
if (isset($_COOKIE['user_role'])) {
    $secret = 'your-secret-key-here';
    list($data_b64, $signature) = explode('.', $_COOKIE['user_role']);
    $data = base64_decode($data_b64);
    $expected_signature = hash_hmac('sha256', $data, $secret);
    
    if (hash_equals($signature, $expected_signature)) {
        $cookie_data = json_decode($data, true);
        if ($cookie_data['role'] === 'admin') {
            echo "Admin panel content";
        } else {
            http_response_code(403);
            echo "Access denied";
        }
    } else {
        http_response_code(403);
        echo "Invalid cookie";
    }
}
?>

05Prevention Checklist

Sign all cookies containing sensitive data
using HMAC or a cryptographic library (e.g., itsdangerous in Python, hash_hmac() in PHP). Verify the signature on every read.
Never store authentication tokens or role information in plain cookies.
Use server-side sessions with a secure session ID instead, or use signed/encrypted tokens (e.g., JWT with a strong secret).
Set the HttpOnly flag
on all cookies to prevent JavaScript from accessing them, reducing the attack surface.
Set the Secure flag
to ensure cookies are only transmitted over HTTPS, preventing interception.
Use the SameSite attribute
(Strict or Lax) to mitigate cross-site request forgery (CSRF) attacks that might exploit cookie manipulation.
Validate cookie data on the server side
every time it is read, not just when it is set. Treat cookies as untrusted input.

06Signs You May Already Be Affected

Check your application logs for unusual cookie values or unexpected role/permission changes. If you notice users suddenly gaining elevated privileges without logging in, or if security tests reveal that modifying cookies in a browser changes application behavior, your application may be vulnerable. Review your codebase for any cookies that are set but never verified with a signature or HMAC.

07Related Recent Vulnerabilities