Cookies without HttpOnly

Sensitive cookie without HttpOnly

Description

Without HttpOnly, client-side JavaScript such as document.cookie can read a cookie. If XSS occurs, an attacker may steal authentication cookies or session tokens and impersonate the user. HttpOnly restricts page scripts from reading cookie values; it does not prevent XSS itself or protect a fully compromised browser.

Potential impact

  • Session hijacking and access to the application as another user
  • Account takeover when combined with long-lived sessions or weak reauthentication
  • Access to sensitive information through a stolen authenticated session

Remediation

  • Set HttpOnly on sensitive server-issued cookies. Specify httpOnly: true in Express and Next.js, or include HttpOnly in Node.js Set-Cookie headers.
  • Also configure Secure for HTTPS-only transmission, SameSite (Strict or Lax), appropriate Path/Domain scope, and expiration (Max-Age/Expires).
  • Prefer HttpOnly cookies to local storage for sensitive session IDs or access tokens, with a server session store and rotation policy where needed.
  • Framework examples:
    • Express: res.cookie(name, value, { httpOnly: true, secure: true, sameSite: 'Strict' })
    • Koa: HttpOnly defaults to true. Do not disable it with httpOnly: false.
    • Next.js Server Function/Route Handler: (await cookies()).set(name, value, { httpOnly: true, secure: true, sameSite: 'strict' })
    • Node http: include ; HttpOnly in the Set-Cookie header.
  • Reduce XSS risk through input validation, output encoding, and CSP.

Examples

Before

javascript
// Before: HttpOnly is missing.
const crypto = require("crypto");
const express = require("express");
const app = express();

app.get("/signin", (req, res) => {
  const token = crypto.randomBytes(32).toString("base64url");
  // Missing HttpOnly allows document.cookie to read the value.
  res.cookie("auth", token, {
    secure: true,
    sameSite: "Lax",
    path: "/",
  });
  res.send("signed in");
});

app.listen(3000);

After

javascript
// After: include HttpOnly.
const crypto = require("crypto");
const express = require("express");
const app = express();

app.get("/signin", (req, res) => {
  const token = crypto.randomBytes(32).toString("base64url");
  // Set HttpOnly, Secure, and SameSite.
  res.cookie("auth", token, {
    httpOnly: true,
    secure: true,
    sameSite: "Strict",
    path: "/",
    maxAge: 10 * 60 * 1000, // 10 minutes
  });
  res.send("signed in");
});

app.listen(3000);

Explanation:

  • Before: Browser JavaScript can read the cookie through document.cookie. XSS may expose it and allow session hijacking.
  • After: HttpOnly blocks script access to the cookie value. Secure and SameSite add transport and CSRF protections. XSS still requires separate prevention.

References