Skip to content

Test your website now

Free, no card. We read only public pages.

Run free audit →

Security · Medium severity

Cookie Without the HttpOnly Flag: How to Fix It

Fix a missing HttpOnly flag on session cookies without breaking frontend code. See header examples, verification steps, exceptions, and scanner limits.

Published · Updated

What the check tests

Check
sec.cookies.httponly - Session cookies HttpOnly
Passes when
Set-Cookie for session-like cookies should include HttpOnly.
Scope
graded on every page crawled
Severity
Medium
Fix effort
small - under an hour
Impact when fixed
medium

In one paragraph

A cookie without the HttpOnly flag can be accessed by JavaScript when its domain and path make it available to the document. For an authentication cookie, that can expose a reusable session token if an attacker executes script on the site. Add HttpOnly server-side to sensitive cookies that frontend code does not need to read, then verify that authentication still works.

Why it matters

HttpOnly prevents JavaScript from reading the cookie through document.cookie and related cookie APIs. The browser still attaches the cookie to matching HTTP requests, including requests initiated by fetch or XMLHttpRequest. A conventional server-managed session can therefore continue working without exposing its token to application scripts.

The main benefit is limiting one consequence of cross-site scripting: direct theft of the cookie value. HttpOnly does not stop injected JavaScript from executing, reading visible page data, or making authenticated requests from the victim's browser. A passing flag check must not be described as an XSS fix.

Not every JavaScript-readable cookie is a security defect. Some consent, interface, or CSRF implementations intentionally expose a value to the frontend. Evaluate the sensitivity and intended reader rather than adding flags blindly.

How WebAuditOS evaluates this finding

According to the supplied specification, this check judges cookies whose names contain session, sid, token, or auth, and excludes names containing csrf or xsrf. Any judged cookie without HttpOnly produces a warning; all judged cookies with it pass. If no session-like cookies are present, the response is not graded.

The name-based rule is a heuristic. It can flag a non-session cookie and miss a real session with an unrelated name. It reads Set-Cookie response headers, not cookies created later by JavaScript. Product-specific matching and grading should be confirmed against the deployed check implementation before publication.

How to fix it

  1. Identify the cookie's role. Use the finding's name and the browser Network panel to locate the response that creates it. Determine whether it is a session identifier, access token, CSRF token, preference, or integration setting.
  2. Search client-side code for reads of that cookie. A frontend that checks document.cookie to decide whether someone is signed in will stop seeing an HttpOnly value. Replace that design with a suitable authenticated session-status endpoint or server-provided user state where appropriate.
  3. Set HttpOnly in the server-side cookie or session configuration. A typical response looks like:

Set-Cookie: session=REPLACE_WITH_TOKEN; Path=/; Secure; HttpOnly; SameSite=Lax

Do not copy the placeholder as a session value. Keep token creation, rotation, expiry, and revocation under the application's session-management implementation.

  1. Apply the setting at the owner of the cookie. In PHP, review session.cookie_httponly for session cookies. In Django, review SESSION_COOKIE_HTTPONLY. In Node applications, use the issuing library's httpOnly cookie option. Check the exact API and configuration for your deployed version.
  2. Test login, logout, refresh, session expiry, and any frontend API calls. For cross-origin API use, credentials and CORS configuration remain separate requirements; HttpOnly does not configure them.
  3. Verify both the HTTP response and the stored cookie. DevTools should show HttpOnly enabled. The cookie should not appear in document.cookie, although other JavaScript-readable cookies may still appear. Confirm the flag again after session renewal and password changes.
  4. Run WebAuditOS again against relevant publicly accessible routes. An external scan without credentials cannot confirm the full behaviour of an authenticated session, so retain manual tests inside your application.

If JavaScript genuinely needs a CSRF value, keep that value separate from the authentication session. Do not expose the session token merely to make a frontend token-reading pattern convenient.

What the fix can break

Code that reads the protected cookie will no longer find it, usually without a helpful exception. That can create false logged-out states, missing request headers, or broken client-side account navigation.

A proxy rule that forces HttpOnly onto every cookie can disrupt legitimate script-readable integration cookies. Conversely, replacing a protected session cookie with localStorage simply to keep JavaScript access removes the HttpOnly protection rather than fixing the design.

Leave intentional exceptions documented, with the cookie's purpose and the reason its value must be readable. Review the exception when its implementation changes.

Questions

Does HttpOnly prevent XSS?

No. It prevents direct JavaScript access to the cookie. An injected script can still act through the current browser session, so output encoding, sanitisation, CSP, and dependency maintenance remain important.

No. Set it through an HTTP response from the server. A document.cookie assignment cannot add HttpOnly to a cookie.

Not always. Some double-submit or frontend-header designs require JavaScript to read a separate CSRF value. Keep the authentication cookie protected and follow the security requirements of the chosen CSRF mechanism.

What should I fix alongside HttpOnly?

Review /checks/security/cookie-without-secure-flag for HTTPS-only cookie transmission and /checks/security/content-security-policy-header-missing for browser-side script restrictions. Neither control replaces the other.

Standards and sources

  • OWASP Session Management

In the report

Test this on your own site

Every scan runs sec.cookies.httponly on every page it crawls, on every plan. The finding carries this id, so a line in a report can be matched to the explanation above - and the free scan needs no account.