Cubby early access
rebuilding in the open · early access — this page ships with the build and changes when the system changes

cubbyapps.com/security · the design contract

Security

Cubby runs applications that other people's AI wrote. We think that sentence should make you ask hard questions, so this page tries to answer them before you do — what isolates your app from everyone else's, where your credentials actually live, who else touches your data, how you leave, and what we are honestly not yet.

read this first — where the build stands

Cubby is in early access, being built in the open by one person. This page describes the architecture Cubby is built to — it is the design contract for the platform, and no claim on it survives a release it isn't true of. Every present-tense sentence below describes how Cubby works today. If you ever read a claim here that you can't verify against how Cubby actually behaves, that's a bug — report it like one.

§01 isolation

the isolation model

Every Cubby app runs in its own V8 isolate on Cloudflare Workers for Platforms — the product Cloudflare built and documents for exactly this job: running untrusted code written by your customers, or by AI. We are not bending a general-purpose host into a multi-tenant one; we are using the multi-tenant one as designed, on the paid plan.

What that means concretely:

  • One isolate per app. Your app never shares a JavaScript heap, a global scope, or an in-memory anything with another app. Each isolate is capped at 128 MB of memory and CPU-metered.
  • One database per app. Every app gets its own Neon Postgres project — its own connection string, its own credentials, its own storage. Not a shared database with row-level tenancy. Not a shared cluster with schemas. A separate project. A bug in one app's queries cannot read another app's rows, because the credential it holds cannot reach the other database at all.
  • No arbitrary code paths. Cubby compiles one blessed stack (TypeScript, React, Vite) from source, through our build pipeline, with a rules gate in front of every deploy that refuses server code anyone could call without signing in. The rest of the rules check (check_app) is advice the AI runs before deploying. There is no Dockerfile lane, no user-supplied binary, no second language. This is a product refusal, not a temporary gap — it is most of why the sandbox is trustworthy.
  • Exact-host dispatch. Requests reach an app only through a dispatch worker that matches the hostname against a host table — exact match, no wildcards resolving to someone else's app.

What is shared: Cloudflare's edge, the dispatch worker, the build fleet — every build runs in a fresh container that is thrown away after that one build — and the platform plan budget. What is never shared: your app's isolate, its database and database credentials, its vault entries, and its workspace identity boundary.

§02 vault

the vault

Connections are how a Cubby app reaches your real systems — Snowflake, an API with a bearer token. The credentials for those connections are the most sensitive thing we hold, so their handling has exactly one rule with no exceptions:

Secret values never transit a chat transcript. Not when you create a connection, not in tool results, not in logs. When your AI adds a connection, you get a setup link; you open it in your browser and the secret goes browser-to-vault over TLS. The model that is building your app never sees it.

At rest, vault entries are encrypted with AES-256-GCM, keys derived with PBKDF2, every ciphertext versioned (enc:v1:) so rotation is an operation, not an archaeology project. Secrets are injected into an app at deploy time, scoped to that app alone, and surfaced to app code only through the typed connections.* SDK interface — never as ambient environment soup.

§03 egress

apps can only call what you allowed

A vaulted credential is only half the story — the other half is where an app is allowed to send traffic. Every tenant app's outbound fetch is intercepted platform-side by a Workers for Platforms outbound worker and checked against a per-connection egress allowlist: the app you connected to your Salesforce can reach Salesforce, not an attacker's collection endpoint. check_app additionally flags code that reaches for raw sockets or random-host fetches when you run it; at runtime, the outbound worker is what enforces the allowlist.

§04 identity

identity and access

  • OAuth 2.1 as specified for MCP (spec 2025-06-18): PKCE (S256) mandatory, exact-match redirect URIs, RFC 8707 audience validation, and a real consent screen that names the human, the client, and the workspace being granted.
  • Every token is scoped to exactly one workspace and is revocable — tokens carry a jti checked against the database on use, so revocation is immediate, not eventual.
  • Apps enforce their own access. Sharing an app is a grant to named people or a workspace, and the app itself checks it via requireUser() against Cubby's OIDC identity — which means access control keeps working even on custom domains and on any future runtime where Cubby isn't in the serving path.
  • Session cookies are host-only (no Domain= attribute — one app's cookie is invisible to every other app and to us), and sign-up through the email link sits behind Cloudflare Turnstile; Continue with Google is Google's own sign-in. The walkthrough request form on this site sits behind Turnstile too.

§05 subprocessors

subprocessors

Cubby is the data processor for what you put in it. These are the subprocessors under the hood — the complete list, and it stays complete:

subprocessor manifest
Subprocessor What it does for Cubby What it can hold
Cloudflare App runtime (Workers for Platforms), edge/CDN, DNS, TLS, Turnstile App code, request traffic in transit, hostnames
Neon Postgres — one project per app, plus Cubby's own control-plane database Your apps' data at rest (encrypted at rest by Neon)
Stripe Billing for paid plans (Stripe's hosted checkout and billing portal) Payment details, billing contact (we never see full card numbers)
Resend Transactional email and walkthrough requests Email addresses; for sign-in emails, the approximate place and browser of the request.

For the Cubby product and your app data: no analytics broker, no session-replay service, no data resale, no training anybody's models on your apps or your data. If this table ever gains a row, the change lands here before it lands in production.

public website

optional website analytics

On the public cubbyapps.com website, optional Metricool analytics measures page visits, traffic sources and country. It loads only after you allow analytics and stays off when your browser sends Global Privacy Control. Metricool says its website tracker uses no cookies; requests carry technical information such as your IP address and browser information, and the IP address is used to determine country. This integration does not run on the Cubby dashboard or customer apps and does not send form contents. Use “privacy & analytics” to change your choice. Declining after allowing reloads the page to stop this tracker; it does not delete earlier measurements.

Read Metricool's privacy policy.

§06 exit

your data: export and delete

The honest version of “no lock-in” is an exit that works while you're still a customer:

  • Export your database any time with the db tool's export action, up to 16 MiB of SQL — larger databases export through a one-hour read-only connection string with pg_dump. Either way it is a standard Postgres export of your app's own database, because it is a real Postgres database, not an abstraction over one.
  • Your app is a standard app. Every Cubby app is an ordinary React/Vite TypeScript project with a small SDK — no proprietary compiler, no runtime magic. If Cubby disappeared tomorrow, your code runs elsewhere with a Node adapter. We rehearse exactly that: a recurring exit drill rebuilds a real app and serves it off-platform, timed and logged — first at launch, then quarterly.
  • Delete, and what it destroys. delete_app (deliberately annotated destructive, confirmation required) takes the app off the internet at once. When the hold below ends, it destroys the app's Neon Postgres project, its source code, its build files, its deployed Worker with the connection secrets bound into it, and its vault entries, and releases its custom domains. The one exception is build files that are byte-for-byte identical to another app's build: they stay while that app is live or still restorable, because they are its build too. What stays of the deleted app is the record that it existed: its name, its address, who it was shared with and its deploy history. Removing a connection destroys its vaulted secret immediately, so remove an app's connections before you delete it if you want them gone now.
  • Deletion starts a 14-day hold: the URL stops serving immediately, nothing is destroyed for two weeks, and you can restore the app — database and all — from the dashboard's Deleted apps any time inside the hold. When the hold expires, its database, its code and its secrets are gone for good.
  • Account deletion: email us and we delete your workspace's apps and destroy their databases, their source code, their build files, their deployed Workers and your vault entries. At our current size that is a human doing it promptly and confirming to you when it's done — we'd rather promise the manual process we actually perform than a self-serve button that doesn't exist yet. Sixty days after you ask, we also erase your account: its email address, its username, your workspace's name and the records of the sign-in links we emailed you — and we sign you out everywhere. If you still belong to another workspace, your account stays for that one. The record of which apps existed, invitations to your address you never accepted, and the billing records (ours and Stripe's) stay on file.

§07 honesty

what we are / what we are not

This section exists because trust built on omission isn't trust.

We do not have SOC 2. Not “SOC 2 in progress,” not a badge from a compliance vendor — we don't have it, and this page won't imply otherwise. What we have instead, today, is a small enough surface to describe completely (you just read it) and an architecture where the strong isolation properties — per-app isolates, per-app databases, per-app vault entries — come from the platform design rather than from policy documents. We haven't had an external penetration test, and this page won't imply one. We test Cubby ourselves — a full security audit of the platform in September 2026, and we fix what it finds — and this page will say when an independent test happens.

Cubby is built and run by one person, and it wasn't invented in a vacuum. We spent years building and running production systems, and more recently putting AI to work inside real businesses. The same gap kept showing up: chat can now produce working software in an afternoon, and there was no serious place for that software to live — nowhere with real isolation, honest answers about data, and a tested way out. So we pivoted, and built that place. Everything above is shaped by those years in production — the architecture encodes the lessons:

  • No arbitrary code — one blessed stack keeps the isolation model small enough to verify completely, instead of a sprawl nobody can audit.
  • Flat platform bill, not metered fear — the runtime costs a fixed $25/month, and every pricing tier's quota exists in code before the tier exists anywhere else, with a global circuit breaker and a daily cost meter behind it.
  • Dunning never darkens your apps. If a workspace's payment fails, deploys pause and apps stay up. A payment problem should be a conversation, not an outage.
  • The exit stays tested — quarterly drills, above, because “we could migrate” is a claim and a timed log entry is a fact.

What to use us for, honestly: internal tools, team apps, the things your company builds in chat and shares with colleagues. If your threat model involves regulated data (PHI, PCI-scope cardholder data) or you need a compliance attestation before procurement will say yes — we are not there yet, and we'll tell you the same thing in a sales conversation.

§08 disclosure

reporting a vulnerability

If you've found a security issue in Cubby, we want it and we'll treat you well.

What we promise

  • Acknowledgment within 3 business days — usually much faster; one person reads this mailbox and cares a great deal.
  • An assessment and remediation plan within 14 days of triage, and we'll keep you posted until it's fixed.
  • Credit by name (or handle, or silence — your choice) once resolved. We do not run a paid bounty program yet; saying so plainly beats implying one.

Safe harbor

Research conducted in good faith — no service disruption, no access to other people's data beyond the minimum needed for a proof of concept, no social engineering of us or our users — will not result in legal action from us. Report what you found, don't keep copies, give us reasonable time before publishing.

Scope

Everything on cubbyapps.com (including api., auth., mcp.cubbyapps.com) and the platform serving layer behind every app. Platform-level issues — isolation, data access, credential handling — are exactly the reports we want most. A logic flaw inside an individual customer app is the app owner's to fix; tell us anyway if you can't reach them and it endangers others.

this page changes when the system changes, and each substantive revision is dated · current revision: 2026-09-30