IPFS Subdomain = Security Risk
If your main app runs on example.com
, don't host your IPFS gateway at ipfs.example.com
. It seems convenient, but it quietly expands your attack surface.
TL;DR
- Treat untrusted content as hostile; give it a separate eTLD+1 (a completely different registrable domain).
- Never put IPFS under a subdomain of your app's domain (same‑site risks, CSRF).
- Use host‑only, HttpOnly, Secure cookies with sane SameSite settings; avoid localStorage for auth.
- If you operate a gateway, force downloads for HTML/JS and add restrictive security headers.
The Real Risk: Same‑Site, Not Same‑Origin
ipfs.example.com
and example.com
are different origins (they cannot directly read each other's localStorage
). But they are the same site because they share the eTLD+1 (example.com
). Same‑site leads to two big classes of problems:
- CSRF and ambient authority
If a user visits a malicious HTML page hosted on ipfs.example.com
, any state‑changing requests it makes to https://example.com
are considered same‑site. With SameSite=Lax/None
cookies (or missing CSRF protections), the browser will attach the user's session cookies, and your app may process the request as if it came from your site.
- Cookie scope and leakage
If your app sets cookies with Domain=.example.com
, those cookies are available to all subdomains, including ipfs.example.com
. JavaScript on the IPFS page can read them unless they are HttpOnly
.
These two together are enough to move money, change emails, or rotate keys if your CSRF defenses are weak. Keeping the gateway under a separate eTLD+1 removes the same‑site relationship entirely.
Note: Scripts loaded via <script src="https://ipfs.example.com/...">
execute in the context of the embedding page (e.g., example.com
) and can read everything. Never embed untrusted scripts, regardless of domain.
What To Do Instead
- Use a separate domain (different eTLD+1) for untrusted content, e.g.
example-ipfs.com
,exampleusercontent.com
, or a trusted third‑party gateway domain. - If you control the gateway, set response headers to prevent active content from executing:
Content-Disposition: attachment
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; base-uri 'none'; frame-ancestors 'none'
- For Open Graph images and static assets, prefer immutable URLs and a CDN; avoid serving HTML directly from the gateway when possible.
- For per‑CID isolation, subdomain your gateway per CID (e.g.,
https://<cid>.ipfs.gateway.tld/...
). This isolates origins between CIDs and, when the gateway is on a different eTLD+1, avoids same‑site with your app.
Cookie & Auth Guidance
- Prefer server‑set cookies over tokens in
localStorage
. - Make cookies host‑only and http‑only. The most robust form is the
__Host-
cookie prefix:
Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
Rules enforced by __Host-
:
No
Domain
attribute allowed (host‑only, not shared with subdomains)Must use
Secure
Path
must be/
Use CSRF defenses on state‑changing routes: SameSite=Lax or Strict, CSRF tokens, and/or server‑side
Origin
orReferer
checks forPOST/PUT/PATCH/DELETE
.
Quick Self‑Check
- Is your IPFS gateway on a subdomain of your app's domain?
- If yes, move it to a separate eTLD+1 (e.g.,
example-ipfs.com
).
- Do any auth cookies include
Domain=.example.com
?
- Make them host‑only or switch to
__Host-
cookies.
- Can a page at
ipfs.example.com
perform a dangerous action onexample.com
without user interaction?
- If yes, add CSRF protections and consider
SameSite=Strict
for high‑risk endpoints.
Bottom Line
- Don't co‑host untrusted IPFS content under your app's eTLD+1.
- Isolate on a separate domain, lock down cookies, avoid localStorage for auth, and implement CSRF protections.
Security starts at the domain boundary. At hey.xyz, we isolate untrusted content to keep user sessions and admin surfaces safe.
Security starts at the domain level. Don't let decentralized storage punch a hole in your centralized app. We follow the same on Hey.