AI chat builder (/chat/build)
On this page
Signed-in users describe a website; each AI turn becomes a versioned snapshot (ai_site_versions, migration 0016)
published as plain static output to R2 SITES and served by the separate sites-worker on <slug>-<id>.devstack.bid
(preview) and <slug>.devstack.bid (production, after Promote).
Security model#
- Generated code is untrusted. It is served only by
sites-workeron*.devstack.bid, never by the platform apex. - Preview iframe: cross-origin,
sandbox="allow-scripts allow-forms"(no same-origin, no popups, no top navigation). - Sites worker headers:
Content-Security-Policy: frame-ancestors https://devstack.bid,X-Content-Type-Options: nosniff, plus a "Built by a devstack.bid user · Report" badge on every HTML page linking to/report(stored in D1site_reports). - Session cookie:
__Host-nvx_auth(Secure, Path=/, no Domain) so a user site cannot set or overwrite it; the legacy host-onlynvx_authis still read so nobody is logged out, and is cleared on the next sign-in or logout. No cookie is set withDomain=.devstack.bid. - Signed-in write APIs (
gate) requireOrigin: https://devstack.bidexactly;*.devstack.bidand requests without an Origin are rejected.sameOriginno longer acceptsSec-Fetch-Site: same-site. - Slugs are globally unique (migration 0017) and platform-like labels are reserved (login, auth, admin, www, api, ...,
anything containing
devstack). - Quota: atomic per-user daily reservation in D1 (
ai_quota,INSERT ... SELECT ... HAVING COUNT(*) < cap) before the model call; KV (nvx-stack-builder-kv) holds only per-minute rate-limit counters. - AI routing: Cloudflare AI Gateway (
CF_ACCOUNT_ID+CF_AI_GATEWAY_ID). In production a direct OpenAI route fails closed (shown as Blocked) unlessAISITE_ALLOW_DIRECT=1. The route is shown only toAISITE_ADMIN_LOGINS.
Long-term fix (not implemented)#
User sites are currently same-site with the platform (same registrable domain devstack.bid). The mitigations above
(__Host- cookie, strict Origin, SameSite=Lax, frame-ancestors) close the known cookie-tossing and CSRF paths, but the
robust fix is to serve user sites from a separate registrable domain (for example devstack-sites.app, listed on the
Public Suffix List the way vercel.app and pages.dev are). That makes user sites cross-site to the platform for cookies,
SameSite, Sec-Fetch-Site and browser storage partitioning. Plan: buy the domain, add a wildcard DNS record + route for the
sites worker, switch PLATFORM_DOMAIN for sites, keep *.devstack.bid as redirects for a deprecation period, then submit
the domain to the PSL.
Source: docs/platform/AI-CHAT-BUILDER.md · /docs/platform/ai-chat-builder.md