You're viewing the readable version of this site. The interactive extras (search, diagrams, read-aloud) need JavaScript and a current browser. Enable JavaScript; if it is already enabled, update your browser.

Notes · Dissecting Real Systems

growing

The Credential That Predates the Origin

Cookies do not obey the same-origin policy — they never have. Thirty years of attributes, flags and name prefixes are one long retrofit, and knowing which parts actually hold is most of session security.

· · 13 min read

security, web, cookies, sessions, http, browsers, dissecting-systems

Cookies do not provide isolation by port… Cookies do not provide isolation by scheme.

HTTP State Management Mechanism §8.5, "Weak Confidentiality"

Cite this
APA
Mangalapilly, Y. J. (2026, August). The Credential That Predates the Origin. Saṃhitā Notes. https://yesudeep.com/blog/the-credential-that-predates-the-origin/
BibTeX
@online{mangalapilly2026the,
  author  = {Yesudeep Jose Mangalapilly},
  title   = {The Credential That Predates the Origin},
  journal = {Sa\d{m}hit\=a Notes},
  year    = {2026},
  month   = {August},
  url     = {https://yesudeep.com/blog/the-credential-that-predates-the-origin/},
  urldate = {2026-08-12},
}
Plain
Yesudeep Jose Mangalapilly. “The Credential That Predates the Origin.” Saṃhitā Notes, 2026. https://yesudeep.com/blog/the-credential-that-predates-the-origin/.
RIS
TY  - ELEC
AU  - Mangalapilly, Yesudeep Jose
TI  - The Credential That Predates the Origin
T2  - Saṃhitā Notes
PY  - 2026
UR  - https://yesudeep.com/blog/the-credential-that-predates-the-origin/
Y2  - 2026-08-12
ER  - 

The one credential that never learned the origin model. The cookie article in the web security series examines the mechanism your session depends on and the boundary it actually draws. By the end you'll know why a sibling subdomain is inside your cookie's trust boundary, what Secure does and does not buy on a site that already speaks HTTPS, why SameSite is not a CSRF solution on its own, how the __Host- prefix smuggles an invariant into a namespace, and which of these are settled and which are still moving.

Start with the mismatch.

The opening piece introduced the origin — scheme, host, port — as the unit the platform draws its boundaries around. The isolation headers, storage, script access, the same-origin policy itself: all of them agree on that tuple.

Cookies agree with none of it, because cookies are older. They begin as what RFC 6265 calls "the so-called 'Netscape cookie specification'" — a vendor document, not a standards-track one — and were standardized retroactively. RFC 6265 arrived in 2011, written by Adam Barth, and its job was to describe what browsers already did rather than to design what they should have done. The same-origin policy grew up alongside them, on a different model, and nothing ever reconciled the two.

Two boundaries, and the gap between them

The same four URLs under two different boundary rules. Everything except cookies distinguishes all four; the cookie jar collapses them into one.

Registrable domain — roughly, the domain you could buy: site.example, not app.site.example. Determined by the Public Suffix List, a hand-maintained file, which is why github.io counts as a public suffix and github.com does not.

The specification is unusually candid about the consequences, in two sections worth reading in full. §8.5, "Weak Confidentiality":

Cookies do not provide isolation by port. If a cookie is readable by a service running on one port, the cookie is also readable by a service running on another port of the same server… For this reason, servers SHOULD NOT both run mutually distrusting services on different ports of the same host and use cookies to store security-sensitive information.

And the one people miss, in the same section:

Cookies do not provide isolation by scheme. Although most commonly used with the http and https schemes, the cookies for a given host might also be available to other schemes, such as ftp and gopher.

Important

Secure does not fix this. It restricts where a cookie is sent; it does not partition the jar by scheme. §8.6 spells out the attack: a network attacker who can impersonate http://site.example may inject a Set-Cookie that the HTTPS server "will be unable to distinguish… from cookies that it set itself." This is a large part of why HSTS matters even on a site that never intends to serve plaintext.

The sibling problem

§8.6, "Weak Integrity", states the structural defect as plainly as a specification ever states anything:

Cookies do not provide integrity guarantees for sibling domains (and their subdomains). For example, consider foo.site.example and bar.site.example. The foo.site.example server can set a cookie with a Domain attribute of "site.example" (possibly overwriting an existing "site.example" cookie set by bar.site.example), and the user agent will include that cookie in HTTP requests to bar.site.example. In the worst case, bar.site.example will be unable to distinguish this cookie from a cookie it set itself.

Anything that can host content on a subdomain of your registrable domain can write cookies your application will read as its own. That includes the marketing site, the status page, the vendor's CNAME, and any subdomain you forgot to decommission.

The shared cookie jar makes subdomain takeover a session-security problem rather than a tidiness problem. An abandoned DNS record pointing at a deprovisioned bucket is not merely an embarrassment; whoever claims that bucket can set cookies for your whole domain.

And Path will not save you, because it was never a boundary:

the Path attribute does not provide any integrity protection because the user agent will accept an arbitrary Path attribute

Imagine an apartment building where every flat has its own lock — except the mailboxes, which are all in one unlocked lobby cabinet with names written on tape. Anyone with a key to any flat can peel off a label and stick on their own. The flats are the origins; the cabinet is the cookie jar. Adding better locks to the flats does nothing about the cabinet.

The retrofit, in four moves

Everything after 1994 is an attempt to give a domain-scoped primitive origin-shaped properties without breaking the web that already existed.

Secure, and what it actually promises

Secure means the cookie is only transmitted over a secure channel. It does not mean the cookie can only be set by one, and it does not partition storage. The gap is small and real: a network attacker impersonating the plaintext origin can still write into the jar the HTTPS site reads.

That gap has been measured. Cookies Lack Integrity: Real-World Implications (Zheng et al., USENIX Security 2015) states the asymmetry in one sentence — a cookie carries a flag for how it may be sent and none for how it was set — and then goes looking for the consequences. The authors report cookie-injection vulnerabilities in sites including Google and Bank of America, worsened by implementation differences they found across Chrome, Firefox and Safari, with outcomes running to account hijacking and financial loss.

The shape of the attack is the article's thesis in operation: an attacker who is briefly on the path of one plaintext request writes a cookie, and the HTTPS site reads it afterwards as its own. Not because TLS failed — the HTTPS connection is perfectly sound — but because the jar it reads from was never keyed on the origin doing the reading.

HttpOnly, and the limit OWASP names

HttpOnly keeps the cookie out of document.cookie, which removes the simplest XSS exfiltration path. OWASP is precise about how far that goes:

The HttpOnly cookie only protects the confidentiality of the cookie; the attacker cannot use it offline, outside of the context of an XSS attack.

Read that carefully. The attacker cannot steal the session, but injected script running in your page can still use it — every authenticated request it makes carries the cookie automatically. HttpOnly converts session theft into session riding. That is a real improvement and not a solution, which is why the CSP piece and this one are both necessary.

SameSite, and why it is not a CSRF fix

SameSite tells the browser not to attach a cookie to requests from another site. Three values, matched case-insensitively: Strict, Lax, None.

Two details matter more than the values.

It is not spelled out as a default. There is no sentence in the specification saying "the default is Lax." The behavior is a consequence of the retrieval algorithm, which admits a cookie cross-site only when its same-site flag is "Lax or Default" — so the unset state is enforced as Lax. That is worth knowing because it is browser-observable behavior with no prose to cite.

And None now costs you something: the storage algorithm ignores the cookie entirely unless Secure is also set.

Warning

SameSite is a defense in depth, not a CSRF solution. The specification permits a "Lax-allowing-unsafe" mode in which a cookie with no explicit SameSite is attached to a cross-site POST for a short window — "deployment experience has shown a cookie age of 2 minutes or less to be a reasonable limit." It is a MAY addressed to browsers, so your protection depends on which browser your user brought. OWASP's guidance is to set the attribute explicitly and never rely on the default.

Worth noting the "site" in SameSite is the schemeful one — HTML defines "same site" as scheme-inclusive and "schemelessly same site" as the registrable-domain-only comparison. So http://site.example and https://site.example are not same-site, which is one place the retrofit did manage to import an origin-shaped property.

Note

SameSite and the Sec-Fetch-Site header from the fetch-metadata piece answer the same question at different layers. SameSite decides what the browser attaches; Sec-Fetch-Site reports what the browser observed, and lets your server decide. The second is strictly more informative, because you can act on it rather than hoping.

The prefixes, which are the good idea

Here is the move worth stealing.

The problem, stated in the specification's own words:

it is impossible for a server to have confidence that a given cookie was set with a particular set of attributes. In order to provide such confidence in a backwards-compatible way, two common sets of requirements can be inferred from the first few characters of the cookie's name.

A cookie arrives as a name and a value. The attributes it was set with — Secure, Domain, Path — are not transmitted back. Your server sees session=abc123 and cannot tell whether it came from your HTTPS origin with no Domain, or from a sibling subdomain over plaintext.

So the invariant was moved into the one field that is transmitted: the name.

If a cookie's name begins with a case-sensitive match for the string __Host-, then the cookie will have been set with a Secure attribute, a Path attribute with a value of /, and no Domain attribute.

The prefix is a guarantee smuggled through a namespace. The browser refuses to store a __Host- cookie that does not satisfy the invariant, so the name's presence is the proof — and a name is the one thing a sibling subdomain cannot forge without also satisfying the rule.

The specification is clear about what that buys, and about the one thing it does not:

This combination yields a cookie that hews as closely as a cookie can to treating the origin as a security boundary… Ports are the only piece of the origin model that __Host- cookies continue to ignore.

Thirty years of retrofit, and the closest approach to the origin model is a naming convention that gets everything but the port. __Secure- is the weaker sibling: it asserts only that Secure was set.

Note

A wart worth knowing if you implement this: revision 22 of the draft says "case-sensitive match" in the prose of both prefix sections, while the storage algorithm steps say "case-insensitive match." That is an editorial inconsistency in the current text, not a subtlety — treat the prefixes as case-sensitive and you will be correct under either reading.

What is still moving

Two things in this area are unsettled, and it is worth knowing which.

Partitioning is shipping without a normative home. CHIPS — Cookies Having Independent Partitioned State — gives a cookie "a separate cookie jar per top-level site," double-keyed by the setting origin and the top-level site. It is Baseline as of December 2025 and works across current browsers. It is also in neither of the live cookie drafts. The individual draft MDN references expired in 2023 and was never adopted by the working group. So the platform is shipping a security-relevant storage change that no current standards document defines.

And the standard itself is being replaced. The document quoted throughout this piece is draft-ietf-httpbis-rfc6265bis, revision 22 — still a draft, in the RFC Editor queue, not yet an RFC after years of work. Meanwhile a newer draft, Cookies: HTTP State Management Mechanism edited by Anne van Kesteren and Johann Hofmann, already proposes to obsolete both RFC 6265 and 6265bis. Its abstract acknowledges the situation with a well-chosen word:

Although cookies have many historical infelicities that degrade their security and privacy, the Cookie and Set-Cookie header fields are widely used on the Internet.

Important

Check the status before you cite any of this. 6265bis has been in the RFC Editor queue and could be assigned a number at any time; the layered-cookies draft expires in November 2026 and will be revised. The behavior is stable because browsers ship it; the documents are not.

Using them for sessions

The mechanism explained, the deployment follows. OWASP's session guidance is worth quoting rather than paraphrasing, because the numbers are the point.

Entropy. "Session identifiers must have at least 64 bits of entropy to prevent brute-force session guessing attacks," generated by "a strong CSPRNG." In hexadecimal that is at least 16 characters. And: "if any part of the session ID is fixed or predictable, the effective entropy is reduced" — a session ID built by concatenating a random value with a user ID has the entropy of the random part alone.

Regeneration. This is the one people skip:

The session ID must be renewed or regenerated by the web application after any privilege level change within the associated user session… The session ID regeneration is mandatory to prevent session fixation attacks, where an attacker sets the session ID on the victim user's web browser instead of gathering the victim's session ID.

Note the inversion that makes fixation work. The attacker does not need to steal your session; they need to give you theirs before you log in. If the ID survives authentication, the attacker's pre-known value is now an authenticated session. The cookie domain boundary gives the attacker one way to set it from a sibling subdomain.

Rejection. "Web applications should never accept a session ID they have never generated, and in case of receiving one, they should generate and offer the user a new valid session ID."

The status page was a static site on a subdomain, built by whoever was on call during the last outage, pointed at a hosting provider nobody had logged into since. It had no login, no database, and nothing worth stealing. That was the argument for not putting it behind the same review as everything else.

It also shared a registrable domain with the application, which meant it shared a cookie jar. When the hosting account lapsed and someone else claimed the subdomain, they did not need to breach anything. They needed to set one cookie with a Domain attribute, and wait.

Nobody had thought of the status page as part of the authentication system. The browser had, all along.

Lessons

  • Cookies are keyed on the registrable domain, not the origin — no port isolation and no scheme isolation, by the specification's own admission.
  • A sibling subdomain is inside your credential's boundary. It can set a Domain cookie your application cannot distinguish from its own, which makes subdomain takeover a session-security problem.
  • Path is not a boundary. The user agent accepts an arbitrary Path.
  • Secure governs transmission, not storage, so a plaintext impersonator can still write into the jar your HTTPS site reads.
  • HttpOnly converts session theft into session riding. Injected script still acts as the user.
  • SameSite is defense in depth. Lax-by-default is an algorithm consequence with no prose to cite, and the spec permits a two-minute exception for cross-site POST.
  • The prefixes encode the invariant in the name, because the name is the only field transmitted back — the closest a cookie gets to the origin model, ports excepted.
  • Regenerate the session ID on every privilege change, or fixation survives authentication.
  • The documents are unsettled even though the behavior is not. 6265bis is still a draft; a replacement already proposes to obsolete it; partitioning ships with no normative home.

Practice

References

  1. Steven Bingler, Mike West, John Wilander (Eds.). “Cookies: HTTP State Management Mechanism.” Internet-Draft, revision 22, 2025. — the working text: Weak Confidentiality, Weak Integrity, the prefixes and SameSite. Still a draft, in the RFC Editor queue
  2. Adam Barth. “HTTP State Management Mechanism.” RFC 6265, 2011. — the 2011 standardization, seventeen years after deployment
  3. Anne van Kesteren, Johann Hofmann (Eds.). “Cookies: HTTP State Management Mechanism.” Internet-Draft, 2026. — the replacement that proposes to obsolete both RFC 6265 and 6265bis
  4. Mike West, Mark Goodwin. “Same-site Cookies.” Internet-Draft, 2016. — where SameSite came from
  5. OWASP. “Session Management Cheat Sheet.” OWASP Cheat Sheet Series. — entropy requirements, regeneration as mandatory, and the HttpOnly limit
  6. WHATWG. “Same site.” HTML Standard. — schemeful same-site, which the cookie draft delegates to
  7. MDN. “Partitioned cookies (CHIPS).” MDN. — double-keyed cookie jars, shipping and Baseline but absent from both cookie drafts
  8. Mozilla. “Public Suffix List.” — the hand-maintained file that decides where the registrable domain begins

How to cite

APA
Mangalapilly, Y. J. (2026, August). The Credential That Predates the Origin. Saṃhitā Notes. https://yesudeep.com/blog/the-credential-that-predates-the-origin/
BibTeX
@online{mangalapilly2026the,
  author  = {Yesudeep Jose Mangalapilly},
  title   = {The Credential That Predates the Origin},
  journal = {Sa\d{m}hit\=a Notes},
  year    = {2026},
  month   = {August},
  url     = {https://yesudeep.com/blog/the-credential-that-predates-the-origin/},
  urldate = {2026-08-12},
}
Plain
Yesudeep Jose Mangalapilly. “The Credential That Predates the Origin.” Saṃhitā Notes, 2026. https://yesudeep.com/blog/the-credential-that-predates-the-origin/.
RIS
TY  - ELEC
AU  - Mangalapilly, Yesudeep Jose
TI  - The Credential That Predates the Origin
T2  - Saṃhitā Notes
PY  - 2026
UR  - https://yesudeep.com/blog/the-credential-that-predates-the-origin/
Y2  - 2026-08-12
ER  - 

Annotations

Thank you — your note is held for review and will appear once approved.

Thank you — your note is published.

Please sign in below to leave a note.