• Terms of Service

Learn Internet Grow

Tech Skills

  • Learn
  • Books
  • Search
  • Create
  • Measure
  • Secure
  • Share
  • Terms of Service

HttpOnly Cookies and XSS: The Flag Stops Theft, Not Use

Filed Under: Secure

RFC 6265, the April 2011 cookie standard, defines the flag in one sentence: “The HttpOnly attribute limits the scope of the cookie to HTTP requests.” Read that sentence the way code injected into your page would. A request sent by fetch() from inside your origin is an HTTP request. The browser attaches the cookie, because HTTP requests are exactly the scope the flag grants.

That is the whole gap between what gets said about HttpOnly cookies and XSS and what the standards actually say. The claim that an HttpOnly session cookie behind a Backend for Frontend makes an application safe from cross-site scripting is the most repeated sentence about the BFF pattern, and it is false. RFC 10017, the IETF’s Best Current Practice for OAuth in browser-based applications, concedes the residual attack in writing. Read a little further and it also shows that the residual attack is not a BFF weakness at all. It is the floor under every browser application that authenticates with a cookie, and it was there long before anyone wrapped OAuth around a session.

A brass key sealed inside a glass case set into a wooden door, turned by an iron lever from inside the room so the door stands open without the key ever leaving the glass

This piece belongs to a set on the Backend for Frontend pattern; the set’s main guide explains the pattern and the three architectures RFC 10017 ranks. The job here is narrower: what the flag blocks, what it cannot, and how to write the difference into a design document without overselling it.

What the flag was scoped to do in 2002, and still does

HttpOnly is older than the standard that defines it. OWASP’s page on the attribute dates it: “HttpOnly support was first added by Microsoft in Internet Explorer 6 SP1 around 2002.” The same page records what it was built against, citing Microsoft’s Michael Howard: “the majority of XSS attacks target theft of session cookies.” The flag was aimed at the dominant attack of its day — script reading document.cookie and posting the value to a server the attacker controlled — and against that attack it works. Script asks for the cookie; the browser declines.

RFC 6265 §4.1.2.6 wrote that behaviour down nine years later, as a scope rule: the cookie goes on HTTP requests and is withheld from the browser APIs that expose cookies to script. Nothing in the definition says anything about who writes the HTTP request.

A sealed brass canister with a glowing token travelling up a glass section of a pneumatic tube, above an open intake hatch on a desk where another canister waits to be sent

The reference documentation has never claimed more than that. OWASP: “It is important to remember that HttpOnly does not block XSS or stop script execution.” MDN’s Set-Cookie reference, loaded on 17 September 2026, spells out the half that folklore drops: “Note that a cookie that has been created with HttpOnly will still be sent with JavaScript-initiated requests”. MDN’s own summary of the benefit is careful with its verb: “This mitigates attacks against cross-site scripting”. Mitigates, not prevents.

So the flag did its job; the job description was inflated. A defence against one move — reading the credential — got repeated as a defence against the attacker. (The other cookie attributes have their own article in this set, and none of them changes the argument below.)

RFC 10017 §5.1.4 concedes the residual attack in writing

RFC 10017 was published in August 2026 as a Best Current Practice, and its datatracker page on 17 September 2026 shows it neither updated nor obsoleted. Its threat model starts from a premise worth pinning above any architecture review: “Attack vectors, such as cross-site scripting (XSS) or the compromise of remote code files, give an attacker the capability to run arbitrary code in the application’s execution context.”

It lists the ways to keep that from happening — context-sensitive output encoding, fewer unchecked third-party resources, Subresource Integrity, a nonce-based or hash-based Content Security Policy, origin isolation — and immediately adds the sentence that makes the rest of the document necessary: “Unfortunately, history shows that even when applying these security guidelines, there is a risk that the attacker might find a way to trigger the execution of malicious JavaScript.”

So the RFC assumes the attacker gets in, and asks what they get. Of its four attack scenarios, the one that matters here is §5.1.4, “Proxying Requests via the User’s Browser”. The attacker steals nothing. In this scenario “there is no need for the attacker to abuse the application to obtain tokens, since the browser will include its own cookies or tokens in the request.” And “The requests sent by the attacker to the resource server are indistinguishable from requests sent by the legitimate application, since the attacker is running code in the same context as the legitimate application.”

Then comes a sentence that describes a BFF without naming it: “Should the client application rely on an external component to augment the request with the proper access token, then this external component will also augment the attacker’s request.” A BFF is precisely that component: a request arrives from the right origin with a valid session cookie, and the BFF attaches the token with no way to know which script wrote the request.

And then the concession, verbatim:

“This attack pattern is well known and also occurs with server-side web applications using HttpOnly session cookies. It is commonly accepted that this scenario cannot be stopped or prevented by application-level security measures. For example, DPoP [RFC9449] explicitly considers this attack scenario to be out of scope.”

Identical blank envelopes on a conveyor passing under an automatic wax-sealing press, with one more identical envelope sliding onto the belt from a side chute

Two notes on reading that paragraph correctly.

First, its last sentence is RFC 10017 characterising another standard, not quoting it. DPoP’s own text, RFC 9449 §2, puts the same concession this way: “there is most likely no feasible defense against this threat except generally preventing XSS; therefore, it is considered out of scope for DPoP.” The characterisation is fair. It is still a paraphrase, and a design document should cite it as RFC 10017 says of DPoP, never as DPoP says.

Second, the RFC repeats the point inside the architecture it recommends most strongly. The BFF’s own threat analysis, §6.1.4.1, says that client hijacking “is an attack scenario that is inherent to the nature of browser-based applications. As a result, nothing will be able to prevent such attacks apart from stopping the execution of malicious code in the first place.” The document that recommends the BFF is the same document telling you it is not a cure for XSS.

Client hijacking and session hijacking are not synonyms

If HttpOnly doesn’t stop the attack, what does it do? RFC 10017 answers in one sentence, at the top of §6.1:

“Note that the use of HttpOnly cookies prevents the attacker from directly accessing the session state, which prevents the escalation from client hijacking to session hijacking.”

That sentence is the honest frame, and both of its terms are defined.

Client hijacking (§5.2.3) is what the attacker has while their code runs in your page: “This effectively allows the attacker to perform any operations that the legitimate client application can perform.” It is also bounded: “Note that client hijacking is less powerful than directly abusing stolen user tokens.” The reason the RFC gives is that “the attacker cannot directly control the tokens and is restricted by the security policies enforced on the client application”.

Session hijacking is holding the session itself — the credential, portable, usable from the attacker’s own machine. The BFF’s cookie section, §6.1.3.2, states the flag’s contribution flatly: “Session hijacking is not possible due to the Secure and HttpOnly cookie flags.”

So HttpOnly is not immunity. It is a blocked escalation. The attacker keeps the first rung and loses the second, and the RFC makes the flag mandatory for exactly that reason: “The BFF MUST enable the HttpOnly flag for its cookies.”

One precision matters if you cite this in a review. The escalation sentence appears twice in RFC 10017, with a different left-hand term each time. The version above belongs to the full BFF (§6.1). The Token-Mediating Backend (§6.2), where the browser does receive an access token, reads “which prevents the escalation from access token theft to session hijacking”. The architecture decides which escalation is blocked, so quote the version that matches the system you are describing.

A lantern-lit ground-floor hall with open drawers and shifted papers, and a closed wrought-iron gate across the staircase leading up to a dark, untouched strongroom

Why “session riding” is the wrong name for it

The folk name for the residual attack is session riding. Searched case-insensitively on 17 September 2026, it returns zero matches in RFC 10017, RFC 9700 and RFC 9449. It does appear in OWASP’s article on cross-site request forgery, which introduces a list with “CSRF attacks are also known by a number of other names” and includes Session Riding in it. That is a name for an attack that arrives from another site.

The residual attack under a BFF does not arrive from another site. It comes from your own origin, which is why cross-site defences don’t touch it. OWASP’s CSRF Prevention Cheat Sheet says so in bold: “Remember that Cross-Site Scripting (XSS) can defeat all CSRF mitigation techniques!” A SameSite=Strict cookie is sent on a same-origin request by definition, and an anti-forgery token sitting in the page is readable by script sitting in the same page.

OWASP’s Session Management Cheat Sheet uses a third vocabulary for the same thing: “However, if an XSS attack is combined with a CSRF attack, the requests sent to the web application will include the session cookie, as the browser always includes the cookies when sending requests.” That is a reasonable shorthand, as long as nobody reads “CSRF” in it as a promise that CSRF defences apply.

TermWhere it comes fromWhat it namesIn a design document
Proxying requests via the user’s browserRFC 10017 §5.1.4The attack scenario: injected script sends requests from inside your originUse it for the mechanism
Client hijackingRFC 10017 §5.2.3The consequence: the attacker can do whatever the app can, while their code runsUse it for the residual risk under a BFF
Session hijackingRFC 10017 §6.1 and §6.1.3.2The attacker controlling the session state itselfUse it for what HttpOnly blocks
Access token theftRFC 10017 §6.2Where the blocked escalation starts in a Token-Mediating BackendOnly when describing that pattern
XSS combined with a CSRF attackOWASP Session Management Cheat SheetThe same residual, in OWASP’s shorthandRecognise it; the request is not actually cross-site
Session ridingOWASP’s list of CSRF synonyms; absent from all three RFCsA cross-site attackAvoid it; it names a different attack

A credential that leaves versus an intruder who has to stay

Saying “not immunity” is true and, on its own, useless in a design review. A reviewer needs the size of the difference, so here are the two failure modes side by side in RFC 10017’s own terms.

Stolen bearer token (token lives in the browser)Client hijacking (BFF with an HttpOnly session cookie)
What the attacker holdsThe credential itself — a string they can copyNothing portable: “there are simply no tokens to be stolen” (§6.1.4.2)
Where it works fromAnywhere; “any resource server that accepts the valid access token” (§5.2.2)Only inside the victim’s browser, in your origin, through your app and your BFF
What it can send“any HTTP method, destination URL, header values, or body” (§5.2.2)What the app can send, “restricted by the security policies enforced on the client application” (§5.2.3)
How longA refresh token commonly stays valid for “multiple hours or even days” (§5.2.1)While the attacker’s script is running in an open page
After the tab closesStill worksStops — until a stored payload runs again on the next page load
What ends itExpiry, rotation, or revocation at the authorization server (§5.2.1)Ending the script or the session: closing the page, removing the injected code, ending the session at the BFF
Where you can see itAt each resource server, as requests carrying a valid tokenAt the BFF, which proxies every request — the RFC’s suggested home for anomaly detection and rate limiting (§6.1.4.1)

RFC 10017’s own summary of the trade sits in §5: “Though the risk of attacker abuse of authorization is unavoidable, there are ways to limit the extent to which a compromised application can abuse that authorization.” Its first example is that “this access might be limited to times when the application is in active use”. That is what a BFF buys. The attacker’s window shrinks from the lifetime of a token to the lifetime of their foothold in an open page. OWASP’s Session Management Cheat Sheet makes the same point from the cookie side: “The HttpOnly cookie only protects the confidentiality of the cookie; the attacker cannot use it offline, outside of the context of an XSS attack.”

A scene split by a stone pillar: on one side a brass key lying far along a moonlit road leading away from an open gate, on the other a small room lit by one low candle

The honest limit of that table

A confined attacker is not a harmless one. For as long as their script runs, they can do anything the application can do, and some of what an application can do is durable: change the account’s email address, change its password, send a purchase to a new address. Once that has happened, the account belongs to them regardless of tabs or cookies.

The defence against that is not a cookie attribute. It is the control OWASP’s Authentication Cheat Sheet names — require the current credentials before sensitive changes — because “Without this countermeasure, an attacker may be able to execute sensitive transactions through a CSRF or XSS attack without needing to know the user’s current credentials.”

Put together, a paragraph that survives a security review can be written in plain terms. Under this design, an attacker who achieves script execution on our origin can act as the user, through the BFF, for as long as their script runs in an open page. They cannot extract a credential, use it from another machine, or keep access after the page closes. Sensitive account changes require re-authentication, so the window cannot be turned into an account takeover. Preventing script execution in the first place — CSP, Subresource Integrity, output encoding, dependency review — remains the primary control.

§7.1.1: the floor was there before OAuth

This is the part almost nobody writes. RFC 10017 runs its threat analysis on one more architecture: an ordinary single-domain application with no OAuth at all, just server-side session state behind a cookie — the server-rendered application most teams shipped before the SPA. Its verdict, §7.1.1, in full:

“Due to the lack of using OAuth, this architecture pattern is only vulnerable to the following attack scenario: proxying requests via the user’s browser (Section 5.1.4). As a result, this pattern can lead to the following consequence: client hijacking (Section 5.2.3).”

That is the BFF’s residual profile, row for row: the same single surviving scenario and the same single consequence. §5.1.4 said as much in advance, when it noted that the attack “also occurs with server-side web applications using HttpOnly session cookies”. And the BFF’s own summary, §6.1.4.3, calls the one remaining attack “a problem inherent to web applications”, adding: “Using a BFF also ensures that the application’s attack surface does not increase by using OAuth.”

A cutaway hillside showing an old stone cottage and a modern glass tower standing on the same bedrock shelf, with one fine fault line running through the rock beneath both

Read those three passages together and the BFF’s real claim comes into focus. It does not make a token-based SPA safer than a server-rendered session application. It makes it exactly as safe, by removing every attack that exists only because tokens reached the browser. The residual risk is not a price the BFF charges. It is the floor under any browser application that authenticates with a cookie, and an argument that treats it as a BFF shortcoming is comparing the pattern against an alternative that does not exist.

What a BFF does nothing about

The BFF changes what an attacker finds after their code is running. It changes nothing about whether it runs, and several failure modes sit entirely outside the browser-to-BFF leg that the cookie protects. It is not a perimeter.

  • Compromised dependencies. RFC 10017 names “the compromise of remote code files” as an attack vector alongside XSS. A poisoned package or a tampered third-party script runs with your origin’s privileges. Under a BFF it finds no token to take, and it can still proxy requests like any other injected code.
  • A compromised BFF. Moving tokens server-side concentrates them. The RFC is direct that “security vulnerabilities in the BFF can have a significant impact on the application”, and HttpOnly — a browser-side attribute — has nothing to say about the server holding every user’s tokens.
  • Malicious browser extensions. None of RFC 10017, RFC 9700 or RFC 9449 discusses them; every hit for the word extension in the three is an OAuth or PKCE extension. Our reading of the RFC’s privilege model: an extension allowed to inject script into your pages is one more source of injected code — no token to take under a BFF, requests still possible.
  • Phishing. Every architecture in RFC 10017 governs tokens and sessions after a user authenticates, so a password typed into a fake login page is compromised upstream of all of them. The RFC never uses the word; this, too, is our reading of its scope.
  • Malware on the device. This is the one case where session hijacking comes back. A process that can read the browser’s cookie store from disk takes the cookie whole, and the RFC notes that even an encrypted cookie “still allows the attacker to use the encrypted cookie in a session hijacking attack”. That attacker has left the browser’s security model entirely, which is why HttpOnly never claimed to cover them.
A stone keep at night with a massive torch-lit iron-banded front door, while a crate is hoisted through an open loading bay, a window stands open and a cellar hatch lies propped open along the side

Moving the residual risk, since you cannot remove it

The residual attack can’t be engineered away at the application layer; RFC 10017 says so, and RFC 9449 agrees. What you can change is how likely it is and how much it costs when it happens.

  1. Stop the script from running. The only control that addresses the attack itself — the §5 list: output encoding, fewer unchecked third-party resources, Subresource Integrity, a nonce- or hash-based Content Security Policy, origin isolation. Each works on the step HttpOnly never touched.
  2. Watch at the chokepoint. A BFF proxies every request, and the RFC turns that into an advantage: “If a high-security application would prefer to implement anomaly detection or rate limiting, such a BFF would be the ideal place to do so.” It adds: “Such restrictions can further help to mitigate the consequences of client hijacking.”
  3. Keep other resource servers strict. Client hijacking is bounded by the security policies around the client, and the RFC’s example is a CORS policy on an admin API that refuses requests from the main web application’s origin. The corollary is spelled out: “A resource server without such a strict CORS policy can still be subject to adversarial requests coming from the compromised client application.”
  4. Make durable changes cost a credential. Re-authentication before password, email and payment changes, per OWASP, so that a live window cannot be converted into a permanent takeover.

None of these is a cookie flag, and that is the point. HttpOnly closed the escalation it was built to close in 2002; the rest of the job always belonged to something else.

❓ Frequently Asked Questions

Does HttpOnly prevent XSS?

No. It prevents script from reading the cookie’s value. It does not stop script from running, and it does not stop the browser from attaching the cookie to requests that script sends. RFC 10017 describes the surviving attack in §5.1.4 and states that it “cannot be stopped or prevented by application-level security measures”.

If it doesn’t stop XSS, is HttpOnly still worth setting?

Yes, and for a BFF it is not optional: RFC 10017 makes it a MUST. It is the difference between an attacker who has to stay inside the victim’s open page and one who leaves with a credential — most of the value of moving tokens out of the browser.

Is a BFF more secure against XSS than a server-rendered app with a session cookie?

No, and the RFC shows it. §7.1.1 gives the plain single-domain session-cookie application the same residual profile as the BFF: one surviving scenario, proxying requests via the browser, and one consequence, client hijacking. The BFF’s achievement is bringing a token-based SPA down to that floor, not below it.

Doesn’t SameSite=Strict stop injected script from using the cookie?

No. SameSite governs whether a cookie travels on cross-site requests, and a request sent by script running in your own page is not cross-site. OWASP’s CSRF guidance warns that XSS “can defeat all CSRF mitigation techniques”. How the attribute works, and why browsers disagree about its default, is covered by this set’s SameSite article.

Would DPoP close the gap instead?

Not this gap. DPoP binds a token to a key so that a stolen token, on its own, is useless elsewhere, which addresses exfiltration. Even that carries a condition that RFC 9449 §2 states itself: malicious script “is also in a position to create DPoP proofs with timestamp values in the future and exfiltrate them in conjunction with a token”, which is why the RFC gives servers nonces to limit how long a proof stays usable. And script running in the live page can use the key the same way the application does, and RFC 9449 §11.4 opens with exactly that: “If an adversary is able to run code in the client’s execution context, the security of DPoP is no longer guaranteed.” How DPoP and a BFF divide the threat model between them has its own article in this set.

What should the residual risk be called in a design review?

Client hijacking, the RFC 10017 term, with its limit stated alongside it: the attacker can act as the user through the application while their script runs, and HttpOnly prevents the escalation to session hijacking. Avoid session riding. OWASP lists it as a synonym for CSRF, it appears in none of the three relevant RFCs, and it implies a cross-site attack that this one is not.


📚 Recommended Resources

Some links below are Amazon affiliate links. If you buy through them, this site earns a small commission at no extra cost to you. The free primary sources come first, because on this subject they are better than any book: every sentence in the article above can be checked against them.

The documents this article is built on

  • RFC 10017 — OAuth 2.0 for Browser-Based Applications (Best Current Practice, August 2026). Read §5 for the threat model and §6.1.4 for the BFF’s own threat analysis, then §7.1.1 for the single-domain comparison most summaries leave out. If you only have twenty minutes, §5.1.4 and §5.2.3 are the ones that matter for this argument.
  • RFC 6265 — HTTP State Management Mechanism (April 2011). The cookie standard, and the one-paragraph definition of what HttpOnly actually scopes. Worth reading precisely because it is so short.
  • RFC 9449 — DPoP (Standards Track, September 2023). Section 2 and §11.4 are where DPoP states, in its own words, the limit that RFC 10017 later summarises.
  • RFC 9700 — Best Current Practice for OAuth 2.0 Security (January 2025). The general OAuth security BCP. None of the five attackers it enumerates in §3 is code running inside the client’s own page (it calls that list “a minimal attacker model”), so read it for everything except browser architecture — that part is RFC 10017’s job.
  • OWASP Session Management Cheat Sheet, CSRF Prevention Cheat Sheet and Authentication Cheat Sheet. RFC 10017 points to the OWASP series itself for cookie and secure-coding guidance. The three here cover the flag’s real guarantee, why XSS defeats CSRF defences, and re-authentication for sensitive actions.

Books worth the money

Grokking Web Application Security — Malcolm McDonald (Manning, May 2024). The broadest and most current of the three. Its publisher lists browser security (sandboxing, the same-origin policy and cookie security), cross-site scripting and cross-site request forgery, and what it calls “session jacking” among its subjects, which is this article’s territory at book length and pitched at working developers.

API Security in Action — Neil Madden (Manning, November 2020). For the server side of the argument: authentication, authorization, audit logging and rate limiting are the headline topics on its publisher page, and the last two are exactly the controls RFC 10017 suggests placing at the BFF. Examples are in Java.

The Tangled Web: A Guide to Securing Modern Web Applications — Michal Zalewski (No Starch Press, November 2011). The oldest book here and still the clearest account of why the browser’s security boundaries sit where they do. It explains the same-origin policy that makes “script on your origin” such a decisive position for an attacker.

ASINs checked 17 September 2026: each ISBN-10 check digit was recomputed from the ISBN-13, and verify_pool.py was run twice; on both runs all three listings resolved and Amazon’s own product title matched the title given here. No newer edition of any of the three is listed on its publisher’s page as of the same date.

Newsletter

Tags

Agentic AI Agentic Development AI AI Agents AI Coding Agents Artificial intelligence Backlinks Blockchain Bounded Context Browser ChatGPT Plugins Claude Code CLPR Context Engineering Cross-Chain Cryptocurrency Developer Tools Distributed Systems DLT Domain-Driven Design Email Google Search HBAR Hedera Hedera Hashgraph Internet LLM Machine Learning MCP Microservices Model Context Protocol News NLP Orchestration Photoshop Productivity Saga Pattern SEO Smart Contracts Software Architecture software engineering Twitter Typescript Web3 Writing

Recent Articles

  • QUIC and HTTP/3: The Protocol That Won Is Being Routed Around October 11, 2026
  • The Mark I Perceptron: The Machine That Learned to See October 11, 2026
  • GraphRAG vs Vector RAG: Knowledge Graphs for AI, Explained October 11, 2026
  • Cardano Tokenomics: How ADA’s Supply Actually Works October 10, 2026
  • Transformer Encoder vs Decoder: How to Read the Diagram October 10, 2026
  • Nobody Checks the Verified Badge: The Real State of Git Commit Signing October 10, 2026

Copyright © 2026 · News Pro Theme On Genesis Framework · WordPress · Log in

Content on this site is produced with the assistance of Large Language Models and edited by a human. It is intended for educational purposes — facts may occasionally be incorrect. If you spot an error, please email Larionovdmitri@learninternetgrow.com.

Affiliate Disclosure: This site contains affiliate links to Amazon and other partners. If you purchase through these links, LearnInternetGrow.com may earn a commission at no additional cost to you. We only recommend products we genuinely believe in.

Privacy Policy · Terms of Service