Security model
The address for security reports isn't published yet.
Every place on HatchWorld runs code somebody else wrote. So the platform treats all place code as hostile, including yours. This page explains what that protects, and what's left to you.
The rule: walls, not judgement
An AI reviews every push. But a model can be talked into things, so the review isn't the wall. The wall is deterministic:
- The sandbox. Code runs in QuickJS with a fresh runtime per event, 50 ms of CPU and 16 MB of memory. No network, no files, no
eval, no imports except the API module. - The type check. Each push goes through strict
tscagainst the published types, then a compile run. A call the types don't declare doesn't publish. - The manifest. Rights come only from
static capabilities, checked by the server. A comment or a string in your code can't add a right. - The key's rights. A personal key can upload drafts. It enables versions only if the owner said so when issuing it.
The AI review sits on top and can only refuse. Anything that isn't a clean answer is a refusal. If the model were fooled, an attacker would get nothing the walls don't already allow.
Who could attack whom
| Threat | What stops it |
|---|---|
| A place's code tries to reach the network, the phone, or another place | The sandbox has no network, files or DOM; each part imports only its API module |
| A place's code tries to learn where players are or what they're called | Scripts get player ids only: no names, no positions, no street distances |
| A place's code shows abusive text to guests | Text a player sees is declared in static texts or comes from a checked source: player answers, LLM answers and pushes pass a text judge first |
| A script loops or hogs the server | 50 ms per event; a script that keeps failing or is slow is switched off, and the owner sees why |
| Someone steals your personal key | It expires (7 days by default), can only upload drafts unless you allowed more, opens only the places you chose, and you revoke it in the app |
| A guest sends a forged action from their phone | Nothing from a phone is trusted. Your server part checks who acts and its own state (that part is yours, see below) |
| Text inside code tries to talk the AI reviewer into "ok" | Code reaches the reviewer inside a frame with a random marker per call, as data. Text in code addressed to the reviewer counts as an attack and blocks the publish |
| A tampered setup file tells your coding agent to run something | install.md contains only our package's commands at a pinned version: no curl | sh, no downloads outside npm, nothing outside the project folder |
What's on you
The walls protect players and the platform from your code. They can't make your code correct.
- Check every input. Payloads come from phones. Narrow before use:
typeof x === 'string',Number(x ?? 0),x && typeof x === 'object' && !Array.isArray(x). - Check who acts. Owner-only actions test
e.isOwner. Answers to a sheet: check theidis one you asked, and keep "already answered" ine.player.state. - Be idempotent. A handler may run twice for one event. Check state before acting.
- Keep no personal data. You only have ids. Keep it that way.
- Keep the key out of files. Only in the
HATCHWORLD_PLACE_KEYenvironment variable: no.env, no config, no commit, no output.place-kitnever prints it or writes it to disk. - Don't write to the reviewer. No comments or strings telling the AI what to answer.
Handing a key to a coding agent
The text you paste to Claude Code or Codex lands in the agent's chat and in its provider's logs. That's why the defaults are short and narrow:
- one place per key, 7 days, drafts only;
- you enable versions yourself, on your phone;
- Revoke sits in the same sheet you issued it from.
If your agent's session is shared or leaks, revoke the key. Issuing a new one takes three taps.
Reporting a problem
Found a way around any of the walls above? Tell us before you tell anyone else: security@….