Safeguard
Application Security•

ASVS 5.0 V3.5.4: Host Separate Applications on Separate Hostnames

ASVS V3.5.4 (Level 2) says apps with different trust levels belong on different hostnames so same-origin policy and cookie scoping protect them. Layout, config and tests.

Safeguard Security Team
3 min read

ASVS 5.0 requirement V3.5.4 says separate applications must be hosted on different hostnames, so you get the protection of the same-origin policy: limits on how documents and scripts from one origin interact with another, and hostname based restrictions on cookies. It is a Level 2 requirement.

In plain words: do not put your admin console at example.com/admin and your user content at example.com/uploads. Give them admin.example.com and a separate domain for user content.

Why it matters

Browsers draw the security boundary at the origin: scheme, host and port. Two apps under different paths of one host share everything. A script injected into one can read the other's pages, call its endpoints with the user's session and read localStorage. A cookie set without a Domain attribute is shared across all paths on the host.

The risky pairing is a high value app, such as an admin panel or payment flow, next to a low trust one, such as a blog, a help center or a place where users upload HTML or SVG. A stored XSS in the blog then becomes an admin takeover. Hosting user generated content on the same origin as the main app is the most common version of this mistake.

How to implement it

Plan hostnames by trust level:

  • www.example.com for the marketing site
  • app.example.com for the main product
  • admin.example.com for internal tools, ideally behind a VPN or identity aware proxy
  • a separate registrable domain such as example-usercontent.net for uploads and untrusted rendering

A separate registrable domain matters for user content because sibling subdomains can still affect each other's cookies: a page on blog.example.com can set a cookie for .example.com that the app will receive.

Scope cookies tightly. Omit the Domain attribute so the cookie is host only, and use the __Host- prefix for session cookies:

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

__Host- cookies require Secure, Path=/ and no Domain, so a sibling subdomain cannot overwrite them.

nginx server blocks, one per app:

server { server_name app.example.com;   include app.conf;   }
server { server_name admin.example.com; include admin.conf; allow 10.0.0.0/8; deny all; }

How to test it

List every hostname and path prefix that serves an application, then check which apps share an origin:

for u in https://example.com/admin https://example.com/blog https://example.com/uploads; do
  curl -sI "$u" | head -1
done

If distinct apps answer on the same host, they fail the requirement. Next, inspect cookies in developer tools: session cookies should show no Domain value, or a host only domain, and the __Host- prefix where possible. Finally, from a page on the low trust host, try document.cookie = "sid=evil; domain=.example.com" and see whether the main app accepts it.

Common mistakes

Path based multi-tenancy for apps with different trust. Paths are not a security boundary.

User uploads served from the app origin. Serve from a separate domain with Content-Disposition and nosniff.

Wide Domain cookies. Domain=.example.com hands the cookie to every subdomain.

Forgotten staging hosts. They often share parent domain cookies with production.

Quick check

Are subdomains enough, or do I need a separate domain?

Subdomains give separate origins, which is the main benefit. For untrusted user content a separate registrable domain also isolates cookies completely.

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.