Sensitive cookies without HttpOnly

Sensitive cookies without the HttpOnly flag

Description

JavaScript can read sensitive cookies that lack HttpOnly. If XSS occurs, the injected script may obtain their values. HttpOnly does not itself prevent XSS.

Potential impact

  • Cookie theft: An XSS payload may read cookie values.
  • Session hijacking: Stolen session cookies may allow impersonation.
  • Information disclosure: Sensitive cookie data may be exposed.

Remediation

  • Set HttpOnly when creating sensitive cookies to prevent JavaScript from reading them.
  • Address XSS through appropriate input validation and output encoding.
  • Configure cookie protections to limit unauthorized access.

Django's CSRF cookie serves a different purpose from its session cookie. CSRF_COOKIE_HTTPONLY=False is not a vulnerability by itself; configure it according to how JavaScript obtains the CSRF token.

Examples

Before

python
# Django cookie settings without the flag
SESSION_COOKIE_HTTPONLY = False

After

python
# Django cookie settings with the flag
SESSION_COOKIE_HTTPONLY = True

Before

python
# Flask cookie settings without the flag
from flask import Flask

app = Flask(__name__)
app.config.update(
    SESSION_COOKIE_HTTPONLY=False,
)

After

python
# Flask cookie settings with the flag
from flask import Flask

app = Flask(__name__)
app.config.update(
    SESSION_COOKIE_HTTPONLY=True,
)

Before

python
# FastAPI cookie settings without the flag
from fastapi import FastAPI, Response
import secrets

app = FastAPI()

@app.post("/set-cookie")
async def set_cookie(response: Response):
    session_id = secrets.token_urlsafe(32)  # An unpredictable session value issued by the server
    response.set_cookie(
        key="session",
        value=session_id,
        httponly=False,
        secure=True,
        samesite="lax",
    )
    return {"message": "Cookie set"}

After

python
# FastAPI cookie settings with the flag
from fastapi import FastAPI, Response
import secrets

app = FastAPI()

@app.post("/set-cookie")
async def set_cookie(response: Response):
    session_id = secrets.token_urlsafe(32)  # An unpredictable session value issued by the server
    response.set_cookie(
        key="session",
        value=session_id,
        httponly=True,
        secure=True,
        samesite="lax",
    )
    return {"message": "Cookie set"}

Explanation

  • Before: Without HttpOnly, JavaScript can read the cookie.
  • After: HttpOnly prevents JavaScript from reading the cookie.

References