Security checklist
Your card will run on other people’s machines, next to agents that can edit their code and run commands. The app does a lot to contain it — but what you ask for, and what you do with it, is on you. This page is the checklist to go through before you share a card, and again before each release.
What the app already guarantees
You do not have to (and cannot) weaken these:
- The card runs in a separate sandboxed process with no access to the app, Node.js, other cards,
cookies or
localStorage, and cannot open windows, navigate the app or draw outside its box. - It can reach nothing — not the network, not files, not agents — except through the SDK, and the app checks every request against the user’s grant.
- Its page loads only files from its own package: no remote scripts, no inline scripts, no
eval. - WebRTC and DNS prefetching are disabled in card pages, so there are no side channels to the network. Forms never navigate, nested frames are removed, and the page cannot write the clipboard.
- Decisions and secrets are asked for in the app’s own window-wide dialog, which a card cannot imitate; your text appears there only as a quote.
- Even with
fs.write,.git, agent and editor settings, CI workflows and package-manager settings cannot be changed, and cards get no file access at all when the workspace is the home folder or a drive root. - Prompts and commands are capped per card (6 and 30 a minute) whichever way they are sent, and queued prompts are dropped when the arrow or the permission goes away.
- Data reaches another card or agent only over an arrow the user drew.
- Secrets typed into
secretsettings never reach the card. - Each copy of a card has its own storage; packages cannot read each other’s.
Before you publish
Permissions
- Every permission is actually used. Remove leftovers — each one is a line in the install dialog and a reason to decline.
- Every permission has a
reasonin plain words. - Rarely needed strong permissions are
optionaland requested at the moment of use. -
networklists specific hosts. No catch-all domains, paste bins, URL shorteners, or*.wildcards you do not need. - You do not use
network.localunless the card is about local servers.
Prompts, tools and commands — the high-risk part
- Nothing from the web, a file, a port or an agent’s output is forwarded into
agents.promptorterminals.run/writewithout the user seeing it first. Otherwise one hostile web page or file can take over the user’s agent (prompt injection). - Prompts built from untrusted text use
submit: false, so the user reviews and sends them. - Commands are fixed strings or built from settings the user typed — never from fetched data. Quote anything you interpolate.
- Tools an agent can call do nothing destructive (write files, run commands, send prompts,
spend money) without
card.ui.confirmfirst. - Tool results that include outside content say where it came from and are kept short.
- You never prompt in a loop. The limit is 6 prompts a minute, and the budget still counts.
Secrets
- API keys are
secretsettings used as{{secret:key}}in headers — never a text field inside your card, never in storage, never in the code or the repository. - Your card does not ask for passwords or keys inside its body. Users are told NeuroSquad never does, and that a real prompt dims the whole window.
- Your card does not need secrets on
localhost— they are never sent there.
Files
-
fs.writeis needed. If you only produce a report, consider emitting it to a note instead. - You write only where the user expects (a folder named in a setting, say), never over configuration, lock files, CI files or scripts that run at build time.
- You use
ifMtimeMswhen you rewrite a file the user may be editing. - You do not read
.envor other secret files unless that is the card’s stated purpose.
Data you show and emit
- Text from outside is rendered as text (
textContent), not HTML (innerHTML). The sandbox stops the worst, but your card can still be defaced or confused. - Ports emit only what their description says.
- You do not act on
windowmessageevents: any card can post to your frame. The SDK’s channel is the only trusted one.
Packaging and updates
-
pack --dry-runlists only what you meant to ship — no.env, keys, private notes,node_modulesor test fixtures with real data. (packrefuses files that look like credentials unless you pass--allow-secret-files.) - Your name and author do not claim to be NeuroSquad, official or verified.
- Your GitHub account has two-factor authentication. Anyone who can push to your repository can ship an update to your users.
- Dependencies are pinned (a lock file), and you rebuild from a clean install before releasing.
- Changes that add permissions ship in their own release, explained.
Behaviour
- The card pauses polling and animations when it is not visible, and saves in
onSuspend. - Network polling is reasonable (the limit is 120 requests a minute — aim far below).
- The card works — degrades, explains — when a permission is revoked.
Found a way for a card to break out of its box, reach something it was not granted, or trick the app’s own dialogs? That is a security bug in NeuroSquad, not in your card — tell the team privately — through the Discord server — rather than in a public thread.
What users are told
The install dialog tells users, in these words, that the card is community code not checked by NeuroSquad, what each permission means at its worst (for example, that with network access “anything the card can see may be sent there”), and that “anything inside the card is the card’s own”. Write your description and reasons so that a careful user, reading those lines, still says yes.