Skip to content
All blog posts

Concept and method · Blog

Related-Domain Attacks: The Collapse of Security Assumptions Delegated to the Browser

The origin and site boundaries browsers enforce do not stop an attacker who sits inside the victim's own domain family. This article describes the cookie, CSP, CORS and framing techniques that chain from control of a single subdomain, with a proof of concept verified in a real browser.

This article was prepared entirely within the framework of fully authorized red team exercises and research conducted in our own lab environment.

You can access our GitHub repository, which serves as the source for the content described in this article, here: https://github.com/redinpulse/RinP-SubChain

Introduction

Modern browsers draw a thick line between origins. Same-Origin Policy, Site Isolation, HttpOnly, SameSite and CSP: every layer exists to keep one site’s data away from another.

In our red team work we regularly reach a position where none of those lines helps. The reason is simple: the organization has given the attacker a place inside the family. Control of a single subdomain is enough for that.

This article describes the chaining techniques we use from that position, the browser protections that stop at the origin line, and the protections that actually hold in the field. It closes with a proof of concept that does not stay on paper: one verified end to end in a real browser.

Who is the related-domain attacker?

The position has a name in the literature: the related-domain attacker. Squarcina and colleagues formalized it in “Can I Take Your Subdomain?”, published at USENIX Security 2021: an attacker who controls a sibling of any one of the victim’s subdomains.

The industry usually reaches this position through a subdomain takeover, but the entry paths are far wider than dangling CNAME records:

  • Expired domains behind aliases that are still live, and decommissioned third-party services (the Shopify, Tumblr, GitHub Pages class) that never revalidate ownership.
  • Released cloud IP addresses that a DNS record still points at.
  • Corporate and roaming networks that hand an FQDN to every device that joins.
  • Hosting and dynamic-DNS providers whose apex is absent from the Public Suffix List. There, every customer site becomes a sibling of every other.

The insight that matters for an operator is this: you do not need an actual takeover to measure the blast radius. The right question to ask before an engagement is a hypothesis: if we controlled a single subdomain of this organization, what would chain across the parent domain? The answer takes minutes and requires nothing more than reading what the victim’s own siblings declare.

Why do browser protections stop at this position?

Because almost every browser protection is scoped to either the origin or the site, and an attacker in this position sits inside both boundaries.

Same-Origin Policy (SOP) isolates origins. The attacker’s subdomain is a different origin, so SOP works exactly as designed; there is no SOP bypass here. But SOP is not the mechanism that decides which cookies travel with a request. That decision is not made per origin; it is made per registrable domain (eTLD+1).

SameSite does not save the situation either. SameSite=Strict and SameSite=Lax restrict cross-site requests, yet every subdomain of the victim belongs to the same site. A Strict session cookie set on app.victim.com travels comfortably to evil.victim.com, because in the browser’s view no site boundary has been crossed. The one subtlety is schemeful same-site: in browsers that enforce it, a controlled subdomain on http counts as cross-site relative to https siblings.

Site Isolation likewise separates sites. Cross-origin attacks within a single site are explicitly outside its threat model; attacker and target can share the same renderer process.

So what does hold? Host-only cookies, meaning cookies that carry no Domain attribute, never leave their own host. The __Host- prefix forbids Domain scoping outright. Those two, together with the TLS requirement on the controlled host before anything marked Secure can be received, are the real defenses at this position. In our experience they are also the controls we encounter least often in the field, which means most applications meet this position unprepared.

This finding matters most in internal environments

The technique is often assumed to be niche because it requires a rare subdomain takeover; in practice the opposite holds. One of the grounds where the finding carries the highest risk, and therefore should be checked first, is internal environments. The reasons are these:

  • Automatic FQDN distribution. Corporate DNS (AD-integrated dynamic DNS, DHCP registration) gives every device that joins the network a hostname under the corporate zone (machine.corp.example). An attacker who compromises a device on the network, joins the network, or registers a name becomes a sibling of internal web applications without needing any external subdomain takeover. Internally, the related-domain position often comes ready-made.
  • Wildcard TLS and wildcard domain. Internal PKI frequently uses a single *.corp.example wildcard certificate for dozens of services. If the domain is a wildcard and the web application is hosted on an FQDN, the controlled internal host can present valid TLS for a sibling hostname. That is exactly what is needed to receive cookies marked Secure and to be a valid https origin. This trio (wildcard, FQDN and hostname) opens a serious risk path.
  • Weak web hygiene under the assumption that the network is already safe. Internal applications frequently use domain-wide cookies (Domain=.corp.example, so SSO works across all services), do not use __Host- or host-only cookies, carry a loose CSP or none at all, apply lax CORS, and omit frame-ancestors. Every precondition the chain needs is more common internally, because the environment is treated as sitting behind the firewall.
  • SSO and OAuth concentration. Internal identity is often single across the domain. A single cookie toss against a domain-wide session cookie or an internal OAuth callback can pivot into many internal applications at once. A narrowly scoped toss that targets the IdP callback through path precedence is high value.
  • Flat trust and a wide blast radius. Internally, everything shares the same registrable domain and domain-wide cookies, so a single hostname registered or compromised by an attacker can chain across the whole fleet of internal applications.

An honest note: this does not mean zero effort. It still requires a device or DNS-record position on the network; split-horizon DNS and environments with a separate zone per tier reduce the sibling relationship; zero-trust internal architectures (per-application authentication, mTLS, host-only cookies) break the impact. That variability is precisely why we say it should be checked first: internally, how far this finding applies varies from environment to environment, so it is not assumed, it is measured.

Building blocks of the chain

Cookie confidentiality

Every cookie set with Domain=.victim.com is sent to every subdomain, including the attacker’s. HttpOnly does not protect against this: HttpOnly only prevents JavaScript from reading the cookie; the browser still attaches it to requests. The attacker has no need for document.cookie. The victim’s own browser delivers the session to the attacker’s server, where the cookie is captured off the wire.

Cookie tossing and shadowing

The same scoping works in the opposite direction. The controlled subdomain can set a cookie with Domain=.victim.com and overwrite the application’s own values (session fixation) or shadow them. Even a host-only cookie can be shadowed: a domain-wide cookie with the same name is delivered alongside it, and the parser on the server side picks one of the values.

The subtlety we use against OAuth-heavy targets is path precedence: cookies with a deeper Path are sent first, so a narrowly scoped toss can poison exactly one endpoint, an OAuth callback for instance, without touching anything else. This is the technique behind published account takeovers at Zoom and at various identity providers.

CSP trust escalation

When a sibling’s Content-Security-Policy contains a wildcard such as script-src *.victim.com, the controlled subdomain becomes an approved script host for that application. This does not count as a CSP bypass in the classic sense; the policy does exactly what it says, and what it says is that the attacker’s host is trusted. The injected script runs inside the application’s own origin, with its cookies, its storage and its same-origin APIs.

CORS with credentials

If a sibling reflects arbitrary origins and sets Access-Control-Allow-Credentials: true, the attacker’s JavaScript can read authenticated responses cross-origin. There is a related finding class we scan for automatically: servers that validate the Origin header with a substring or suffix check. A check written as endsWith("victim.com") also accepts evilvictim.com, an entirely different registrable domain, without any subdomain being needed at all.

Framing and postMessage

A missing X-Frame-Options or frame-ancestors lets the controlled origin frame the sibling. A postMessage listener that trusts same-site senders then hands over everything the page is willing to answer. On legacy targets we also check for document.domain relaxation, which turns a sibling into full same-origin access.

Proof of concept: verified in a real browser

Claims about the cookie jar deserve proof at the browser level, so we built a lab that mirrors a realistic target one for one. The lab contains an application dashboard with an HttpOnly domain-wide session, a host-only CSRF cookie, a JWT in localStorage, personal data in the DOM, and an authenticated same-origin profile API. Alongside it sits a second sibling carrying a naive postMessage listener. Every technique below was actually executed and observed in Chromium rather than inferred from headers.

The capture that ends the discussion happens through the CSP wildcard. A script served from the controlled subdomain and permitted by the victim policy runs inside the application origin and beacons the application’s own data to the attacker’s server:

{
  "cookie": "strictck=1; csrftoken=csrf-9f3a1",
  "localStorage_auth_token": "eyJhbGci.ATTACKER-SHOULD-NOT-SEE.b64",
  "dom_secret": "PII: Gedik Testuser, [email protected], TR",
  "profile_api": {"user": "Gedik Testuser", "mail": "[email protected]",
                  "role": "admin", "api_key": "sk-live-7742"}
}

The HttpOnly session cookie that this script could not see arrived anyway with the request to the controlled subdomain, and was captured server side. The SameSite=Strict cookie came with it. After a single toss from the controlled subdomain, the application itself reported this:

strictck=1; csrftoken=csrf-9f3a1; session=FIXATED; csrftoken=EVILSHADOW

One request changed the session value and placed a shadow cookie next to the host-only original. The only thing the browser rejected, exactly as the spec states, was a __Host- prefixed cookie delivered with a Domain attribute: refused the moment it arrived. That refusal is the model every defender should be aiming at.

The port rule in a CSP host-source

The campaign also produced an empirical rule we have not seen documented cleanly anywhere: in Chromium, a CSP host-source that carries no port part matches only the default ports of the scheme. So *.victim.com trusts your subdomain on 443 but refuses it on 8443, unless the policy lists that port or the :* expression. Five policy variants, one browser, one afternoon:

Policy source expression Loads the script on :8901
*.victim.com blocked
http://*.victim.com blocked
*.victim.com:8901 allowed
http://evil.victim.com:8901 allowed
http://*.victim.com:* allowed

For auditors the result matters in both directions: a wildcard without a port is still a live chain on standard ports, while a source with a port tells you exactly which port the host you control has to serve on.

The tool: RinP SubChain

We packaged the methodology as a single-file audit tool with no dependencies. You give the tool the victim’s registrable domain, a list of sibling subdomains, and the subdomain you assume to be under your control; it audits every sibling and reports the chain classes together with the conditions they depend on: RECEIVABLE, TOSSABLE, SHADOW, PROTECTED, SCOPED-DEEPER, TRUSTED-CSP directives, CORS chains including the suffix-validation finding, and framable hosts. A serve mode deploys onto the subdomain you control as a capture endpoint, and a toss helper comes with it for fixation tests.

Two design decisions keep the tool honest. First, there is no discovery: you supply the scope, and the tool does not go looking for subdomains on its own. Second, classifier semantics were calibrated against a real browser, and that decision paid off immediately.

Live internet runs against large properties showed one subtle case: Cloudflare’s own __cf_bm cookie is set with Domain=www.cloudflare.com, a deep-scoped cookie that reaches only the subdomains of that host. A tool that audits the cookie domain against the registrable root would mark it RECEIVABLE, whereas auditing against the host you actually control classifies it correctly as SCOPED-DEEPER: still shadowable, but not delivered. GitHub’s logged_in cookie, by contrast, is Domain=.github.com and HttpOnly; from a hypothetical controlled-subdomain position it is receivable and tossable server side. Listing exactly that finding class is why the tool exists.

If you would rather see the chain than read bullet points, the repository also contains the lab we proved it in. One command, python3 lab/server.py, brings up the victim dashboard, the naive sibling and an attacker console in your own browser: a live capture log of everything your browser delivers to the controlled subdomain, buttons for toss, shadow and __Host- attempts, a CSP variant switcher that demonstrates the port rule live, and a postMessage playground. The walkthrough in lab/GUIDE.md turns every claim in this article into something you watch on your own machine.

What this means for organizations

The defensive list is short and uncompromising:

  • Sensitive cookies: wherever a session or CSRF decision is made, they should be host-only (no Domain attribute) and carry the __Host- prefix.
  • CSP: there should be no wildcards covering subdomains you do not fully control. Remember that strict-dynamic changes the rules and that ports are part of the trust too.
  • CORS: use exact origin allowlists, never a suffix or substring check, and keep credentials off unless both origins are yours.
  • Framing: frame-ancestors on every sibling, postMessage listeners audited for origin checks, and document.domain retired.
  • DNS hygiene: clean up dangling records, and treat every third-party service that binds to a subdomain as what it really is, a trust delegation.
  • Audit internal more strictly than the external surface: the trio of wildcard certificate, domain-wide cookie and dynamic DNS is the norm internally, which is why the related-domain chain often produces its highest real impact there.

If even one of your subdomains can be taken over by an outside actor, the question to ask is not whether it can phish your users. The real question is this: what will your other subdomains hand over to it?

Measure your own blast radius

The same audit runs against your own domains: give RinP SubChain your registrable domain, your subdomain list, and a hypothetical controlled host. The chain report tells you exactly which cookies, which CSP directives and which CORS endpoints would leak across the family, before an outside actor answers that question on your behalf.

Run this audit for your internal domains in particular. When a wildcard certificate, domain-wide cookies and dynamic DNS come together, that is where the biggest surprises come from.

Concepts and abbreviations in this article

Related-domain attacker

The attacker position that controls one subdomain in the victim's domain family. Because it shares the registrable domain with the target, it sits inside cookie-scoped and site-scoped controls.

Registrable domain (eTLD+1)

The registrable name one label above a Public Suffix List suffix. SameSite and Site Isolation operate on this unit, and cookie scoping derives from it as well.

Host-only cookie and the __Host- prefix

A cookie with no Domain attribute travels only to its own host. The __Host- prefix forbids Domain outright and requires Secure together with a root Path.

Cookie tossing and shadowing

Setting a domain-wide cookie from a controlled subdomain to overwrite the application's value (fixation) or to have a second cookie with the same name delivered alongside it (shadowing).

Blast radius

The total area of impact reachable from one starting position. Here it measures how far control of a single subdomain travels across the parent domain.

// BLOG

Have the blast radius of your domain family measured

By clarifying your subdomain inventory and a hypothetical controlled host together, we can verify which cookies and directives would leak across the family through a controlled engagement.