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 sharehttps://tuturuuu.com, script running
in any one of them can do all of the following:
fetchany 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-ancestorsstops framing, but it cannot stopwindow.openfrom 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.
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.
__Host- cookies that subdomains
cannot toss, once every app is on the apex.
Admission requirements (per app)
- 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:sandboxwithoutallow-same-origin, or aContent-Security-Policy: sandboxresponse header. They must never be same-origin documents. See current exposures. - Strict CSP, enforced. Use nonce-based
script-src 'nonce-…' 'strict-dynamic'with nounsafe-inlineorunsafe-evalfor scripts. Setobject-src 'none',base-uri 'none'andframe-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. - 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. - Path-scoped
connect-src/frame-src. Defense in depth: listhttps://tuturuuu.com/<app>/andhttps://tuturuuu.com/api/plus the app’s external hosts, never'self'. Meet’s CSP then forbidsfetch('/mail/api/...'). CSP ignores the path after a redirect, so this is a speed bump, not a boundary. - The shared session cookie is
HttpOnly. See session cookies. - Permissions-Policy per document. Only Meet documents enable
camera,microphone,display-captureandautoplay. Every other app’s documents sendcamera=(), microphone=(), display-capture=(), which blocks use even when the origin holds a grant. This does not stop thewindow.open('/meet/...')route, so that remains a residual risk (see the core trade). - No storage, message or SW cross-talk.
- Prefix every
localStorage/IndexedDB/Cache Storage key andBroadcastChannelname with the app slug. postMessagehandlers must not treatevent.origin === location.originas proof of a trusted sender. Use dedicatedMessageChannelports or explicit, validated message types.- Register no service worker, or one scoped to
/<app>/.
- Prefix every
- 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 sharedtuturuuu.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 whentuturuuu_app_sessionis 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-Dataon 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:
- Strict CSP is enforced, not report-only: nonce-based scripts and no
unsafe-inlineorunsafe-eval. A report-only policy is not admission. This depends on the bridge supplying a per-request nonce to the router (ssr.nonce). - Trusted Types is enforced (
require-trusted-types-for 'script'), with named policies only for audited sinks. - 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.
- No same-origin
postMessageor storage trust between apps without explicit validated message types. - 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.
- 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(decideincludeSubDomains/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-originon API and private responses.X-Frame-Options: DENYplusframe-ancestors. This follows the existingTUTURUUU_ANTI_FRAMING_HEADERSand Mailresponse-policy.tsbehavior.- Per-app CSP and Permissions-Policy, as above. Private pages keep
Cache-Control: private, no-storeandX-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), anHttpOnly 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.