Skip to content

Security model ​

Who can do what ​

WhoCan
You at your terminal (holding the Open Cloud key and the signing key files)build, upload, approve, sign and deploy any branch; roll back; pin; publish the kernel; rotate keys
An agent, a script or the remote-claude dev-serverbuild and upload, then only write a proposal; you approve it with typetorch approve (y/N). The dev-server never targets a prod-channel branch
Owner in gameeverything a dev can, plus the dev menu's Manage tab (kick, ban, bring, shut down and migrate servers, load a build on other dev servers), switching the server they are in to any branch or build (prod included), and rolling back prod-channel servers
Dev in gamethe dev menu and /tt: read everything; on dev-channel servers also cheats, pins and branch switches. The dev-only tools (Claude, Logs > Upload, Dex edits, Network blocking, Server > Experiments) work under dev rules for every dev, and on a public server an owner switched to a dev branch for owners only
Playernothing beyond your game's own network leaves, which are rate-limited, shape-limited and type-guarded
  • Owners are the experience's creator (or the owning group's owner) and members with the role "owner". Everyone else in members is a dev; the old role "admin" counts as dev.
  • Dev status is decided on the server by the kernel: the experience owner, members, dev-badge holders, Studio; minus revoked. Every dev-menu request is re-checked on the server.
  • members, revoked and devBadgeId reach servers only through bun run typetorch access push. It writes them into the game's signed settings record (kernel 0.3.8+), signed with both prod keys. Game code can write the DataStore it lives in but can't sign, and servers refuse a record that doesn't verify: a backdoored model can't make itself an owner. Run it after every change. Revoking takes effect within seconds (the CLI pings the servers), or within about a minute. deploy and doctor warn when typetorch.json lists people that were never pushed, or changed since the last push (until then a revoked dev stays a dev).
  • Public servers are always effective prod: read-only dev menu, and (kernel 0.3) only signed deploys and signed pins from outside the server.

What protects prod ​

  1. Approval: deploys to branches your approval policy covers wait for your y/N at an interactive terminal.
  2. The cloud test: a prod build boots in your place, headless, before it is published (Deploy and rollback).
  3. Signatures: every prod-channel release is signed with your two Ed25519 keys; kernel 0.3 servers verify it (Prod signing). Code running inside your universe (a dev branch, run_luau, a free model, a package) can't make a prod server load anything new.
  4. Payload shape: a payload holds only Folders and ModuleScripts under one Model, checked when it is built and again when a prod server mounts it; nothing in an upload runs by itself.
  5. Channels: dev branches run only in private or reserved servers, or where you put them (signed A/B pins you approved, or an owner's switch of one server).
  6. Safe deploys: a build that fails on a server is rolled back there, and deploy --wait rolls the branch back when it fails on many (Safe deploys).

What stays open, by design or for now:

  • Dev-channel servers accept unsigned deploy messages: anything that can publish MessagingService messages in your universe can point a dev server at another build.
  • An owner can run any known build on the prod server they are in. Known builds come from the deployment list, which game code can write. It changes that one server only; the payload checks still apply.
  • A public server an owner switched to a dev branch takes that branch's unsigned deploys until it is switched back to prod or closes.
  • The boot fail-safe may boot an unverified stored head when nothing verifies.
  • Group members with asset write access can change the key asset.
  • The stored heads and the settings record live in your universe's MemoryStore and DataStores, which game code can write; prod servers re-verify everything they read there.
  • Settings rollback by replay: game code can't forge the settings record, but it can write back an older signed copy (say, from before you revoked someone). Running servers refuse a lower seq; a server that starts meanwhile takes the old copy until the next write. If you suspect it, write again (typetorch access push gives a new seq) and check typetorch settings status.
  • The game key in the settings record (backend.key) is readable by any server code in your universe, as the old ConfigService keys were. They are write-only tokens; never put a read token there.
  • Cross-server messages (TypeTorch.messaging): the sender tags (JobId, branch, channel) are for routing, not proof. Anything that can publish to your universe's MessagingService can forge them; check what a message asks for.

The backend ​

The backend is meant to sit on a public https address. Its full model is in the backend README's Security section, sign-in and the explorer's roles in The explorer, and the Open Cloud key's scopes per backend feature in Running the backend. The short version:

WhoHow they get inCan
Game serversthe game key (TYPETORCH_API_KEY) as a Bearerwrite events, heartbeats, deploy reports, alerts, error logs, notification intents; read nothing
Adminthe admin token (TYPETORCH_ADMIN_TOKEN; the CLI, or the explorer's token login), or an owner signing in with Robloxread and manage everything
Viewer (the web role)Sign in with Roblox only, for the UserIds in TYPETORCH_WEB_VIEWERS (or the Settings page)read the game's data; every write answers 403; never the server's configuration or game servers' IP addresses
A named keyttk_... as a Bearer, with a role (game, lookup, support, analyst, admin)only its role's scopes (API keys); an admin key can't replace the owner list or the trust-link keys
The lookup tokenTYPETORCH_LOOKUP_TOKEN as a BearerGET /v1/identity/resolve only
  • Owners are the access list the CLI sends with every settings write (PUT /v1/access, admin token only). Removing an owner or a viewer ends their sessions on their next request. Sign-in also works through typetorch.dev, which only confirms who someone is: the role still comes from the backend's own lists.
  • Sessions are signed JWTs in an HttpOnly, SameSite=Strict cookie, valid 3 days from sign-in (TYPETORCH_SESSION_MAX_DAYS; no idle timeout). They survive restarts and deploys; changing the admin token ends them all. A cookie request that changes something also needs the X-TypeTorch: 1 header and, when the browser sends an Origin, this site's. There is no CORS.
  • Lockouts: 5 failed logins or bad tokens in 15 minutes from one address get 429 until the oldest ages out (TYPETORCH_LOGIN_MAX_FAILURES, TYPETORCH_LOGIN_WINDOW_MINUTES). Wrong game keys are counted on their own, so a real game server behind a shared Roblox address is never blocked.
  • Admin allow list: TYPETORCH_ADMIN_ALLOW_IPS (addresses and CIDR ranges) makes the admin routes, the explorer and the login answer 404 to everyone else. Game routes stay open. TYPETORCH_TOKEN_LOGIN=off hides the token login in the browser (the CLI's Bearer still works). Both can be changed on the Settings page, behind guards that refuse to lock you out.
  • Proxies: client addresses come from X-Forwarded-For only with TYPETORCH_TRUST_PROXY (1 behind Coolify or Caddy), and then the proxy must be the only way to the port (TYPETORCH_TRUSTED_PROXIES enforces it). Behind Cloudflare's proxy use TYPETORCH_CLOUDFLARE=on or a DNS-only record, or the allow list and the lockout see Cloudflare's address instead of yours.
  • Audit log: settings changes, key creates and revokes, per-player reads by API keys, remote debug commands and the other admin actions are written to the audit log (the Audit page), never with a secret.

Devtools reach devs only ​

With kernel and framework 0.5.6+, the dev menu's client code (devtools) is not in the client tree every player gets. The server copies it into each dev's own PlayerGui when they join or become a dev; other players never receive it. Older kernels or frameworks ship it to every client as before (still gated on the server).

Keys and tokens ​

SecretWhere it livesNever
Open Cloud API key(s)the game repo's .env (gitignored; CLI 0.9), or the real environmentin git, in chat, in an issue, in a screenshot, given to an agent
Signing key files~/.config/typetorch/keys/<universeId>.key and .fallback.keyinside any git work tree (the CLI refuses), copied to another machine you don't control
Backend admin token (TYPETORCH_ADMIN_TOKEN)the game repo's .env and the backend's environmentanywhere a game server or a client can read it
Named API keys (ttk_...) and the lookup token (TYPETORCH_LOOKUP_TOKEN)the one tool that uses it (its secret store or environment)in a game server, a client, or a shared chat
Backend game key (TYPETORCH_API_KEY, write-only)the game repo's .env and the backend's environment; the signed settings record's backend section (server only)in code, in a payload, sent to a client
Basin R2 token (SQL reads)your PC onlyin the game's settings
Erasure webhook secret (ROBLOX_WEBHOOK_SECRET), alert webhook URL, the backend's Open Cloud keys (OPENCLOUD_API_KEY, OPENCLOUD_NOTIFY_KEY), the notification signing key (TYPETORCH_NOTIFY_KEY or notify-keys.json)the backend's environment and data folder (the webhook URL in runtime-settings.json when saved on the Settings page)in git; a downloaded backup leaves the webhook URL and notify-keys.json out
remote-claude pairing codesyour terminal and clipboardin a commit (they expire after one use or 3 hours)
typetorch serve --remote pairing linksyour terminal (serve status), then the person you send it toin a public channel (one use, 15 minutes; paired devices are listed by serve devices)
  • The CLI keeps keys and tokens in memory, gives each one only to the client for its job, never prints them, and redacts them from errors. Child processes (rbxtsc, rojo, lune, git) get an allowlisted environment without keys.
  • Game servers get only write-only tokens. They can send analytics and fleet data, never read it.
  • Prefer separate keys per job (OPENCLOUD_ASSETS_KEY, OPENCLOUD_DEPLOY_KEY, OPENCLOUD_PLACE_KEY), an expiry date and an IP allowlist. An asset:write key that leaks is as bad as code execution on your servers: keep asset:write on one IP-limited key.
  • Before a live game depends on it: an offline backup of the key files and the .env, the separate asset:write key, and a dated rotation drill (Prod signing: back up and drill).
  • A key acts with its owner's group permissions. Give builders and contractors no Edit access on the production experience.
  • If a key leaks: revoke it in Creator Hub at once and create a new one. If a signing key leaks: typetorch keys rotate (main) or typetorch keys init --fallback --force + kernel deploy (fallback). If a token leaks: rotate it. For the game key, put the new one in the backend's TYPETORCH_API_KEY, the old one in TYPETORCH_API_KEY_PREVIOUS (both accepted until you remove the old one), put the new one in the game repo's .env, and run backend setup again. For the admin token, change TYPETORCH_ADMIN_TOKEN on the backend (that ends every explorer session) and in the game repo's .env. For a named API key: revoke it (DELETE /v1/admin/keys/<id>, or typetorch keys revoke <id> from the next CLI release) and create another (API keys).

typetorch serve and remote Studios ​

  • The control API listens on 127.0.0.1 only. Every request needs X-TypeTorch: 1, a loopback Host and no Origin, and there is no CORS, so a web page can't call it. serve's children (rbxtsc, rojo, your --with scripts) get the CLI's minimal environment, without keys; the hot asset jobs run inside serve with your keys.
  • --remote opens a gateway (127.0.0.1:34890) behind a public tunnel. Only a paired device gets in: a one-time code (15 minutes; 5 wrong codes lock pairing until a new code), then a device token kept hashed in .typetorch/serve-remote.json, valid 30 days or until serve unpair. A remote Studio syncs code read-only (never Rojo's write or open), and its hot asset buttons upload with your keys and deploy only to the dev branch. Pair only people you would give that to.
  • --claude lets the Roblox users in --claude-users (default: the owners in typetorch.json) prompt Claude Code on your machine, in Code mode, with remote-claude's rules (below). Deploys from it follow your approval policy.

No CI for your game ​

TypeTorch ships no GitHub Actions or other hosted CI for games, and nothing in it needs your Open Cloud key or signing keys in a CI system: hosted CI is a common supply-chain risk, and it would need those keys. Builds, cloud tests, signing and deploys run on your own machine. approve --import <dir> exists for automation you choose to run yourself.

TypeTorch's own npm packages are released from a version tag by a GitHub workflow, with npm trusted publishing and provenance (Releases). That workflow holds no Roblox key and never touches a game.

Never publish secrets ​

  • .env, .env.*, .typetorch/ and the key files stay out of git (the template's .gitignore covers the first three; key files live outside the repo). The backend repo ignores .env files and data/.
  • Ids (universe, place, group, user, asset) are not secrets, but keep examples and docs on fake ones.
  • A quick tunnel URL is public while it runs: anything behind it must check its own tokens (the backend does).
  • Before you push or publish a package, search the change for anything that looks like a key.

Agents ​

The agent playbook forbids agents to create, read or store keys, publish places or deploy. If an agent runs a deploy command anyway, the CLI only writes a proposal (it isn't an interactive terminal), but the build is still uploaded with your key: keep keys where agents can't read them (outside the repo, not in the agent's environment).

Released under the MIT License.