Safeguard
Application Security•

CWE-1004 Sensitive Cookie Without HttpOnly: Cause and Fix

A session cookie that scripts can read is one XSS bug away from account takeover. Learn what CWE-1004 means and how to set HttpOnly in common frameworks.

Safeguard Security Team
6 min read

A session cookie is a bearer credential. Whoever holds it is the user, as far as the server is concerned. So where that cookie can be read matters a great deal.

CWE-1004 covers the case where the product uses a cookie to store sensitive information but does not mark the cookie with the HttpOnly flag. With the flag set, the browser keeps the cookie out of reach of page scripts. Without it, any JavaScript running on the page can read it.

MITRE lists it as a Variant that applies to web applications and web servers, in any language. If your application sets cookies, it applies to you.

How it happens

Cookies are set in one of two places: in a Set-Cookie response header from the server, or through document.cookie in client side JavaScript. Both paths can omit the flag.

Common reasons it gets missed:

  • The framework default does not set it, and nobody changes the default.
  • Several services in a chain each set their own cookies, and one is configured differently.
  • Client side code writes a sensitive value into document.cookie. A cookie written that way cannot be HttpOnly, because script created it.
  • A library handling sessions leaves the flag off unless asked.

The observed examples on the MITRE page cover all of these. CVE-2024-47833 is a Python library for machine learning and data science that does not use the HttpOnly attribute for session cookies. CVE-2022-24045 is a room automation web application whose client side JavaScript sets a sensitive cookie without the attribute, so it can be accessed. CVE-2014-3852 is a CMS written in Python that omits the flag in a Set-Cookie header, and CVE-2015-4138 is an appliance for managing encrypted communications that does not use it either.

Here is the vulnerable pattern in two common forms:

// Vulnerable: Express session cookie readable by page scripts
app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: { httpOnly: false }
}));

// Vulnerable: a token written from the browser
document.cookie = "session=" + token;

And the fix:

// Fixed
app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: { httpOnly: true, secure: true, sameSite: "lax" }
}));

In Python with Flask, the equivalent settings are SESSION_COOKIE_HTTPONLY = True and SESSION_COOKIE_SECURE = True. In a raw header, the result looks like this:

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

What an attacker gains

HttpOnly is a second line of defense. It does not stop cross-site scripting from happening. It limits what the script can steal. MITRE records two consequences.

  1. Confidentiality. If the flag is not set, sensitive information stored in the cookie may be exposed to unintended parties.
  2. Integrity. If the cookie is an authentication cookie, an adversary may steal authentication data such as a session ID and assume the identity of the user.

That second point is why the flag gets so much attention. An XSS flaw in a page with an HttpOnly session cookie lets an attacker act in the page. An XSS flaw with a readable cookie lets them copy the session and use it elsewhere, later, from their own machine.

How to find it

MITRE lists automated static analysis, or SAST, as a way to find some instances. A scanner can read your session configuration and your calls to cookie setting functions and flag missing flags.

You can also check by hand in a few minutes:

  1. Open your site in a browser, sign in, and open the developer tools storage panel. The cookies list has an HttpOnly column. Any session or token cookie without a tick deserves a question.
  2. In the console, run document.cookie. Whatever it prints is readable by script. Your session cookie should not be in that output.
  3. Use curl -I against login endpoints and read each Set-Cookie header.
  4. Search source code for document.cookie = and for cookie configuration blocks.
  5. Check every service, including admin consoles, internal tools and third party apps behind your domain.

A dynamic scan of the running application catches headers that source review misses, such as those added by a proxy.

How to fix it

MITRE's mitigation for this weakness is direct: use the HttpOnly flag when setting a sensitive cookie in a response. It rates the effectiveness as high, with a caveat worth reading.

The caveat is that the flag protects cookies from the browser's own scripting engine. Third party components or plugins may have their own engines that allow access to cookies. Attackers might also be able to read headers directly with XmlHttpResponse and obtain the cookie that way.

So treat the flag as one layer, and do these things alongside it:

  1. Set HttpOnly on every session and authentication cookie. Make it the default in your shared session middleware so new services inherit it.
  2. Stop writing sensitive values from client side script. Let the server issue the cookie.
  3. Add Secure and SameSite. They are separate controls, but they usually belong on the same cookies.
  4. Fix the XSS too. HttpOnly reduces the damage. It is not a substitute for output encoding and a good Content Security Policy.
  5. Update session libraries. Several of the CVEs above are in libraries and products, not custom code.
  6. Add a test. A small integration test that asserts the flag on login responses stops regressions.

Try it yourself

This demo shows a dynamic scan of a web application, including the cookie and header checks that surface this issue.

Click through it at your own pace, or open it full screen.

If your session handling comes from a library, you can check that library's known issues with the free in-browser scan at gold.safeguard.sh/scan. No login, the file stays on your machine, up to 100 dependencies.

Quick check

Does HttpOnly prevent cross-site scripting?

No. It limits what a script can read. An attacker with script execution can still act inside the page, but cannot copy the cookie through document.cookie.

Can a cookie set with document.cookie be HttpOnly?

No. HttpOnly can only be set by the server in a Set-Cookie header. Sensitive cookies should be issued by the server for that reason.

What limits does MITRE note for the flag?

Third party components or plugins may have scripting engines that can reach cookies, and attackers might read headers directly with XmlHttpResponse.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.