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: truein Express and Next.js, or includeHttpOnlyin Node.jsSet-Cookieheaders. - Also configure
Securefor HTTPS-only transmission,SameSite(StrictorLax), 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
; HttpOnlyin theSet-Cookieheader.
- Express:
- 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.