# Security checklist

> What the sandbox already guarantees, and the checklist for authors before sharing a card — least privilege, prompt injection, secrets, network, files, commands and updates.

Source: https://docs.neurosquad.ai/en/card-sdk/security

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 `secret` settings 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 `reason` in plain words.
- [ ] Rarely needed strong permissions are `optional` and requested at the moment of use.
- [ ] `network` lists specific hosts. No catch-all domains, paste bins, URL shorteners, or
`*.` wildcards you do not need.
- [ ] You do not use `network.local` unless 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.prompt` or `terminals.run/write` without 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.confirm` first.
- [ ] 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 `secret` settings 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.write` is 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 `ifMtimeMs` when you rewrite a file the user may be editing.
- [ ] You do not read `.env` or 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 `window` `message` events: any card can post to your frame. The SDK's
channel is the only trusted one.

**Packaging and updates**

- [ ] `pack --dry-run` lists only what you meant to ship — no `.env`, keys, private notes,
`node_modules` or test fixtures with real data. (`pack` refuses 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](https://docs.neurosquad.ai/en/help/faq#discord) — 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.
