Skip to main content
Status: proposed, phase 1 (design only). This page gates admission to the one-origin super-app. An app may not be routed onto tuturuuu.com until it meets every admission requirement below with exact-commit evidence. Open critical/high findings hold the release, per the repository security default.

The core trade

The browser’s security boundary is the origin (scheme + host + port). Paths are not a boundary. Once Meet, Mail and Web share https://tuturuuu.com, script running in any one of them can do all of the following:
  • fetch any same-origin URL with the user’s cookies and read the response (/api/*, /mail/api/*). CORS no longer applies.
  • Open or frame another app’s page (window.open('/mail/...')) and script its DOM. frame-ancestors stops framing, but it cannot stop window.open from same-origin script.
  • Read and write every app’s localStorage, sessionStorage, IndexedDB and Cache Storage, and enumerate or unregister service workers.
  • Use any permission the user granted to the origin. A camera or microphone grant for Meet also covers a script injected into Mail.
Therefore: an XSS in any mounted app is an XSS in all of them, Web’s dashboard included. The session is shared by design. Per-app CSP and frame rules reduce accidents and raise attacker cost. They do not restore isolation. The rest of this page is about keeping XSS out and limiting what a successful one can reach.

What changes compared with subdomains

The subdomain model already shares a lot:
  • The Supabase auth cookie is set with Domain=.tuturuuu.com, so every subdomain receives it.
  • Any subdomain can set (toss) a cookie for the parent domain.
  • Supabase SSR cookies are script-readable by default. Verify whether ours are. If they are, an XSS on any subdomain can already steal the session.
One origin adds the four capabilities listed above: response reading, storage, same-origin window scripting and shared permission grants. One origin also enables something the subdomain model cannot: host-only __Host- cookies that subdomains cannot toss, once every app is on the apex.

Admission requirements (per app)

  1. No untrusted active content on the origin. User-generated or third-party HTML and scripts must render on a separate sandbox origin (planned *.tuturuuu-usercontent.com), or in an opaque-origin sandbox: sandbox without allow-same-origin, or a Content-Security-Policy: sandbox response header. They must never be same-origin documents. See current exposures.
  2. Strict CSP, enforced. Use nonce-based script-src 'nonce-…' 'strict-dynamic' with no unsafe-inline or unsafe-eval for scripts. Set object-src 'none', base-uri 'none' and frame-ancestors 'none' (or a path-specific 'self' where framing is required). Report-only is for burn-in on the subdomain; the policy is enforced before the app is routed onto the apex in any mode.
  3. Trusted Types, enforced. Burn in require-trusted-types-for 'script' report-only, then enforce it before the app is routed onto the apex. Rich-text editors (Mail’s Tiptap) get a named policy.
  4. Path-scoped connect-src/frame-src. Defense in depth: list https://tuturuuu.com/<app>/ and https://tuturuuu.com/api/ plus the app’s external hosts, never 'self'. Meet’s CSP then forbids fetch('/mail/api/...'). CSP ignores the path after a redirect, so this is a speed bump, not a boundary.
  5. The shared session cookie is HttpOnly. See session cookies.
  6. Permissions-Policy per document. Only Meet documents enable camera, microphone, display-capture and autoplay. Every other app’s documents send camera=(), microphone=(), display-capture=(), which blocks use even when the origin holds a grant. This does not stop the window.open('/meet/...') route, so that remains a residual risk (see the core trade).
  7. No storage, message or SW cross-talk.
    • Prefix every localStorage/IndexedDB/Cache Storage key and BroadcastChannel name with the app slug.
    • postMessage handlers must not treat event.origin === location.origin as proof of a trusted sender. Use dedicated MessageChannel ports or explicit, validated message types.
    • Register no service worker, or one scoped to /<app>/.
  8. Security review. An independent reviewer signs off on the app’s CSP, cookie and content inventory at the exact head that gets routed.

Session cookies

Decision (user, 2026-10-25): one shared tuturuuu.com session, no per-app split. The Start bridge lane designs the implementation. This page records the requirements it must meet.
  • One session cookie on the apex is valid for every app. Web and every mounted app accept the same token. There are no per-app names, no Path=/<app> scoping and no per-app audience tokens on the apex.
  • Web must stop treating the session cookie as a satellite marker. Today createClient(request) (packages/supabase/src/next/server.ts) returns an unauthenticated client when tuturuuu_app_session is present. Web must neither drop nor clear the shared session.
  • Attributes: HttpOnly, Secure, SameSite=Lax, Path=/, host-only. Use __Host- once no subdomain needs it, so subdomains cannot toss or overwrite it. Refresh and rotation are single-writer: concurrent refreshes from two apps must not invalidate each other.
  • Logout from any app ends the session for all of them. Clear-Site-Data on logout is acceptable for that reason.
  • Mounted apps never write or clear per-app session cookies on the apex.
  • There is no cross-host handoff. Users who already hold the root session stay signed in; only users without one sign in once on the apex at cutover (recorded decision). Subdomains keep their current cookies until they only redirect.
  • The decision is conditional on a clean independent security review of refresh rotation, CSRF and the XSS blast radius below. Anything beyond that scope goes back to the user.

What the shared session changes in the threat model

A per-app path-scoped cookie never protected against same-origin script; the core trade above already holds. The shared session removes the remaining speed bump: an XSS in any mounted app acts with the full session for every app and Web’s dashboard. It can call any app’s API as the user and reach every app’s data. HttpOnly stops the token being read, but script on the origin does not need to read it to use it. That raises the admission bar. Before any app is routed onto the apex:
  1. Strict CSP is enforced, not report-only: nonce-based scripts and no unsafe-inline or unsafe-eval. A report-only policy is not admission. This depends on the bridge supplying a per-request nonce to the router (ssr.nonce).
  2. Trusted Types is enforced (require-trusted-types-for 'script'), with named policies only for audited sinks.
  3. No user-generated or third-party active content on the apex. Email HTML, playground previews and uploads render on a separate sandbox origin, or in an opaque-origin sandbox with a regression guard. “Low risk because scripts are disabled” is no longer enough on its own.
  4. No same-origin postMessage or storage trust between apps without explicit validated message types.
  5. Independent security review of each app’s CSP, sinks and content inventory at the exact routed head. An open critical or high finding holds the route.
  6. Session hardening: short access-token lifetime with refresh, re-authentication (aal2) for sensitive actions, and CSP violation monitoring that can trigger a route rollback.

Shared security headers

Each app Worker applies one portable header builder (planned @tuturuuu/utils/security-headers, framework-free). Web applies the same baseline through its Next config:
  • Strict-Transport-Security: max-age=63072000 (decide includeSubDomains/preload separately; it affects every subdomain).
  • X-Content-Type-Options: nosniff.
  • Referrer-Policy: strict-origin-when-cross-origin.
  • Cross-Origin-Opener-Policy: same-origin. This isolates the app from cross-origin openers, not from same-origin peers.
  • Cross-Origin-Resource-Policy: same-origin on API and private responses.
  • X-Frame-Options: DENY plus frame-ancestors. This follows the existing TUTURUUU_ANTI_FRAMING_HEADERS and Mail response-policy.ts behavior.
  • Per-app CSP and Permissions-Policy, as above. Private pages keep Cache-Control: private, no-store and X-Robots-Tag.

Current exposures

Residual risk and its owner

The residual risk is an XSS in any mounted app acting with the shared session for every app, including media permissions granted to Meet. The release authority accepts it once per app at admission. Mitigations: enforced strict CSP and Trusted Types (prevention), an HttpOnly shared session (token theft, not misuse), path-scoped connect-src (casual exfiltration) and per-document Permissions-Policy (silent media use). CSP violation reports from every mounted app feed one monitored sink, and a new violation class is triaged as a potential release hold.