Closed Bug 1964767 (CVE-2025-8037) Opened 1 year ago Closed 10 months ago

Nameless cookies can be used to shadow Secure cookies from an insecure connection

Categories

(Core :: Networking: Cookies, defect, P2)

Firefox 140
defect

Tracking

()

RESOLVED FIXED
141 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr128 --- wontfix
firefox-esr140 141+ fixed
firefox140 --- wontfix
firefox141 + fixed

People

(Reporter: sormus.uku, Assigned: valentin)

References

Details

(Keywords: csectype-other, reporter-external, sec-moderate, Whiteboard: [necko-triaged] [necko-priority-queue][adv-main141+][adv-ESR140.1+])

Attachments

(4 files, 2 obsolete files)

Steps to reproduce:

(Also see the automatic Playwright tests attached.)
Manually:

  1. Open a new tab to https://x.response.ee/ (the "target", on a secure connection); open the devtools Console tab
  2. Open a new tab to http://y.response.ee:8080/ (the "attacker", from an insecure connection, in schemelessly same-site scope); open the devtools Console tab
  3. In the first, "target" window, set a new Secure cookie by running the following JavaScript:
document.cookie = "csrf_token=secret123; Secure; Path=/"
  1. In the "attacker" window, try to shadow the "target" cookie (create a competing cookie) by running the following JavaScript:
document.cookie = "csrf_token=attacker-controlled1; Domain=response.ee; Path=/"
  1. Observe that the cookie is NOT shadowed, by executing console.log(document.cookie) in "target" window; attacker's cookie setter was unsuccessful
  2. In the "attacker" window, try to shadow the "target" cookie again with a nameless cookie, by running the following JavaScript:
document.cookie = "=csrf_token=attacker-controlled2; Domain=response.ee; Path=/"
  1. Observe that the cookie IS shadowed, by executing console.log(document.cookie) in "target" window; attacker's cookie setter was successful

Actual results:

Nameless cookies can be used to shadow cookies with the Secure attribute from an insecure connection (plaintext HTTP)

Expected results:

Shadowing Secure cookies from insecure connections is disallowed by the current browser behavior, respective code, and the upcoming cookie 6265bis spec.

Note: for Chromium, this MAY be a duplicate of: https://issues.chromium.org/issues/40060605 (I can't access the issue, guess is based on comment from public issue https://issues.chromium.org/issues/40060539#comment13; found this before submitting the same bug to Chromium)

Exception: cookies with the __Secure- or __Host- name prefix are NOT directly affected by this bug, as nameless cookies have been abused in the past to bypass __Host- and __Secure- security guarantees, and therefore are disallowed to be the prefixes of a nameless cookie's value (at least trivially). See:

HttpOnly on the original cookie has NO effect on the possibility of the attack.

Attack scenario:

  • victim visits (or is forced to visit) an insecure origin, which is (at least partially) under the control of the attacker
  • control means the ability to at least set a cookie via JavaScript (document.domain) or headers (Set-Cookie)
  • the attacker may be: a) an active network attacker (insecure origin may be forced upon the victim from, e.g., a redirect from a coffee shop Wi-Fi's captive portal); b) an attacker that has gained control of a subdomain that is in the schemelessly same-site scope with target app (subdomain takeover); or c) plain old XSS-type of vulnerability exists in the schemelessly same-site scope
  • path scoping could further be used to bring the attacker's cookie in front of the original cookie, if needed for the attack by the target server

Direct impact: loss of integrity -- the server has no way of telling that the cookie that was set as Secure, came back "modified" from an insecure origin (apart from two cookies with the same names being in the request -- does any well-known server by default drop cookies for such a situation?).
Indirect impact is dependent on the target application. For example, it is possible to shadow Secure CSRF tokens for the double-submit pattern from an insecure connection that is in the schemelessly same-site scope, while it would be otherwise possible only from secure origins without this bug.

For reference: schemelessly same-site = eTLD+1 a.k.a. registrable domain must match (e.g., http://1.dev.example.co.uk/ and https://bank.example.co.uk both have the eTLD+1 of example.co.uk); exact host match is needed if eTLD+1 is null in a few edge cases like IP-addresses

Source code & specs

See https://searchfox.org/mozilla-central/source/netwerk/cookie/CookieStorage.cpp#629-638

Similarly for Chromium: https://source.chromium.org/chromium/chromium/src/+/main:net/cookies/cookie_monster.cc;l=1500-1510;drc=5fe0c7b2435bb2d92f434a81272b6752a5f34b9b

The recommendations from the mentioned spec draft https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone have been copied to the upcoming RFC6265bis section 5.7 step 16: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-20#section-5.7-3.16.1:

16. If the cookie's secure-only-flag is false, and the request-uri does not denote a "secure" connection, then abort these steps and ignore the cookie entirely if the cookie store contains one or more cookies that meet all of the following criteria:
1. Their name matches the name of the newly-created cookie.
2. Their secure-only-flag is true.
3. Their domain domain-matches the domain of the newly-created cookie, or vice-versa.
4. The path of the newly-created cookie path-matches the path of the existing cookie.
Note: The path comparison is not symmetric, ensuring only that a newly-created, non-secure cookie does not overlay an existing secure cookie, providing some mitigation against cookie-fixing attacks. That is, given an existing secure cookie named 'a' with a path of '/login', a non-secure cookie named 'a' could be set for a path of '/' or '/foo', but not for a path of '/login' or '/login/en'.

This bug may indicate some changes are needed to the wording -- names, indeed, do not match (with empty str).

Another scenario to consider is, if a cookie X is set first from an insecure origin, and then from a secure origin with the Secure attribute, should the "equal"-considered insecure cookie be evicted? This is currently not the case.


Nightly 140.0a1 (2025-05-02) (64-bit)

Group: firefox-core-security → network-core-security
Component: Untriaged → Networking: Cookies
Product: Firefox → Core

This current issue is indeed a (Chromium) duplicate of https://issues.chromium.org/issues/40060605 reported in 2022 that I can now access and also see that Mozilla's Daniel Veditz is CC-d on. I don't know if there's an issue filed under Bugzilla.

From Daniel's comment under here https://bugzilla.mozilla.org/show_bug.cgi?id=1779993#c13, which is public, we can also read (emphasis mine):

For example, normally an attacker can't overwrite an HttpOnly cookie from a non-HTTP context (e.g. document.cookie), and we don't let a non-secure cookie overwrite a secure cookie. This trick [using nameless cookies] doesn't literally overwrite them, but it can create spoofing copies.

I filed a separate issue for the HttpOnly case that I haven't seen filed before:

I'm surprised we didn't file a bug on this explicitly back when we were addressing bug 1779993—we certainly knew about it and I don't remember why we didn't. Maybe because it was a known spec problem (discussed in cookie spec issue #1210) that we decided we had to live with.

I'm very close to saying "to hell with nameless cookies—webcompat be damned!" and just break anyone that tries it

Note that the CookieStore API explicitly disallows a nameless cookie with "=" in the value. It would be nice to do that much, at least. But that's easy to do in a new API where you don't have to worry about existing sites.

I agree with the thing you are very close to saying :-) If the upcoming cookie spec is not yet set in stone, why shall we set ourselves up for such a trap of endless little (security) loopholes, client-server differentials, monkey-patching, implementer and user misery, ... that will be regretted in the future.

I could understand if this was a widespread usage pattern. Has there been actual usage data thrown around in spec discussions around nameless cookies? From Squarcina's "Cookie Crumbles" https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf#page=10, from page 10, there's a table about analyzing nameless cookies in top 100K websites. From that analysis, nameless cookies are very rare and seem like a configuration mistake almost always (TOP 4: nameless cookies with the values HttpOnly, (empty string), Secure and =).

Severity: -- → S3
Priority: -- → P2
Whiteboard: [necko-triaged] [necko-priority-queue]
Assignee: nobody → valentin.gosu
Duplicate of this bug: 1964945

One thing I hadn't noticed before is that Safari actually seems to be rejecting nameless cookies completely https://wpt.fyi/results/?label=experimental&label=master&aligned
So maybe convincing Chrome to do the same wouldn't be so hard considering comment 3, and ideally this would also be picked up by cookie RFC bisbis

Echoing my comment in D250043:

  • RFC 6265 forbids cookies with no equal sign (§5.2 step 2)
  • browsers supported them anyway (echoing back what they got). rfc6265bis presumed that was required for webcompat and added support
  • Despite RFC 6265 explicitly forbidding nameless cookies (§5.2 step 12.3.3), rfc6265bis supported "equal-less cookies" as nameless values
  • Safari never changed from handling them as valueless cookies (treating plain foo; as foo=;, not =foo; as rfc6265bis now requires)

Valueless names make more sense in the web context: Set-cookie: itself supports secure and httponly as valueless attributes, and HTML supports valueless attributes as well. And getting rid of nameless cookies eliminates the need for all these special rules about values containing an equal sign.

Unfortunately we can't use data like that referenced in comment 3 or from http archive data to "prove a negative". We've seen many many times that what sites do with cookies after you log in can be quite different than what's seen in those surveys. User telemetry can miss rarely-used but important sites (like a gov't tax site that's used once a year) but for cookie changes it should a minimum bar. Even with telemetry we've been repeatedly bitten in the ass by cookie changes.

Attachment #9488723 - Attachment is obsolete: true
Group: network-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 10 months ago
Resolution: --- → FIXED
Target Milestone: --- → 141 Branch

We should fix this in ESR-140.1 as well. We may want to skip the nearly EOL ESR-128 and ESR-115: in the unlikely case this breaks sites (which is always likelier than we thought) we wouldn't have much time to detect and then fix the problem before we're out of releases.

QA Whiteboard: [sec] [qa-triage-done-c142/b141]
Flags: qe-verify-

Can we get an ESR140 nomination for this when you get a chance? Thanks!

Attachment #9499142 - Flags: approval-mozilla-esr140?

firefox-esr140 Uplift Approval Request

  • User impact if declined: Nameless cookies can be used to shadow Secure cookies from an insecure connection
  • Code covered by automated testing: yes
  • Fix verified in Nightly: yes
  • Needs manual QE test: no
  • Steps to reproduce for manual QE testing: n/a
  • Risk associated with taking this patch: low
  • Explanation of risk level: The code is well-covered by tests and we haven't seen regressions in nightly
  • String changes made/needed: n/a
  • Is Android affected?: yes
Flags: needinfo?(amarchesini)
Attachment #9499142 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+

Baku, could you rebase your patch to the ESR 140 branch? It failed to land due to conflicts, thanks.

https://lando.moz.tools/D256404/

Flags: needinfo?(amarchesini)
Flags: needinfo?(amarchesini)
Whiteboard: [necko-triaged] [necko-priority-queue] → [necko-triaged] [necko-priority-queue][adv-main141+]
Whiteboard: [necko-triaged] [necko-priority-queue][adv-main141+] → [necko-triaged] [necko-priority-queue][adv-main141+][adv-ESR140.1+]
Attached file advisory.txt (obsolete) —
Attached file advisory.txt
Attachment #9500510 - Attachment is obsolete: true
Alias: CVE-2025-8037

(In reply to Uku Sõrmus from comment #3)

I agree with the thing you are very close to saying :-) If the upcoming cookie spec is not yet set in stone, why shall we set ourselves up for such a trap of endless little (security) loopholes, client-server differentials, monkey-patching, implementer and user misery, ... that will be regretted in the future.

The spec actually already says:

Per the grammar above, servers MUST NOT produce nameless cookies (i.e.: an empty cookie-name) as such cookies may be unpredictably serialized by UAs when sent back to the server.

Related discussion: https://github.com/httpwg/http-extensions/issues/2229

For the record, we'll be changing this on our end in our upcoming release to stop accepting nameless cookies and making cookies without an = valueless, instead. The spec seems to be very clear what to do (or what not to do, rather). There's no reason to risk a class of sec bugs resulting from this if it's clearly not specced behavior.

Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: