# 安全检查清单

> 沙箱已经保证了什么，以及作者在分享卡片前要过一遍的检查清单——最小权限、提示词注入、密钥、网络、文件、命令和更新。

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

你的卡片会在别人的电脑上运行，旁边就是能修改他们代码、运行命令的智能体。应用做了大量工作来约束它——
但你申请什么、用它做什么，责任在你。本页是分享卡片之前、以及每次发布之前都要过一遍的检查清单。

## 应用已经保证的事

这些你不需要（也无法）削弱：

- 卡片运行在单独的沙箱进程中，无法访问应用、Node.js、其他卡片、Cookie 或 `localStorage`，不能打开窗口、不能让应用跳转，也不能在自己的方框之外绘制。
- 除了通过 SDK，它什么都访问不到——网络、文件、智能体都不行——而应用会把每个请求与用户的授权核对。
- 它的页面只加载自己卡片包中的文件：没有远程脚本、没有内联脚本、没有 `eval`。
- 卡片页面中禁用了 WebRTC 和 DNS 预取，因此不存在通往网络的旁路。表单永远不会跳转页面，嵌套的框架会被移除，页面也无法写入剪贴板。
- 决定和密钥由应用在它自己覆盖整个窗口的对话框中询问，卡片无法模仿；你的文字在那里只会以引用的形式出现。
- 即使有 `fs.write`，`.git`、智能体和编辑器的设置、CI 工作流以及包管理器设置也无法被修改；当工作区是主文件夹或磁盘根目录时，卡片根本得不到文件访问权限。
- 无论以何种方式发送，每张卡片的提示词和命令都有上限（每分钟 6 条和 30 条），而当箭头或权限消失时，排队中的提示词会被丢弃。
- 数据只能沿用户画出的箭头到达另一张卡片或智能体。
- 输入到 `secret` 设置中的密钥永远不会到达卡片。
- 卡片的每份副本都有自己的存储；不同卡片包之间无法读取彼此的数据。

## 发布之前

**权限**

- [ ] 每项权限都确实用到了。删掉残留的——每一项都是安装对话框中的一行，也是用户拒绝的一个理由。
- [ ] 每项权限都有通俗易懂的 `reason`。
- [ ] 很少用到的强权限设为 `optional`，在使用时再申请。
- [ ] `network` 列出的是具体主机。不要用包罗万象的域名、粘贴板服务、短链接服务，或你并不需要的 `*.` 通配符。
- [ ] 除非卡片本身就是关于本地服务器的，否则不要使用 `network.local`。

**提示词、工具和命令**——高风险部分

- [ ] 来自网页、文件、端口或智能体输出的任何内容，都不会在用户看到之前被转发进 `agents.prompt` 或 `terminals.run/write`。
否则，一个恶意网页或文件就能接管用户的智能体（提示词注入）。
- [ ] 由不可信文本构造的提示词使用 `submit: false`，由用户检查后发送。
- [ ] 命令是固定字符串，或由用户自己输入的设置拼成——绝不来自抓取的数据。拼接进去的内容都要加引号转义。
- [ ] 智能体能调用的工具在没有先 `card.ui.confirm` 的情况下，不做任何破坏性操作（写文件、运行命令、发送提示词、花钱）。
- [ ] 包含外部内容的工具结果会注明来源，并保持简短。
- [ ] 绝不在循环中发送提示词。上限是每分钟 6 条，而且预算照样计入。

**密钥**

- [ ] API 密钥是 `secret` 设置，并以 `{{secret:key}}` 的形式用在请求头中——绝不是卡片内的文本输入框，绝不放在存储里，绝不出现在代码或仓库中。
- [ ] 你的卡片不会在正文中索要密码或密钥。用户已被告知 NeuroSquad 从不这样做，而且真正的询问会让整个窗口变暗。
- [ ] 你的卡片不需要在 `localhost` 上使用密钥——它们永远不会被发送到那里。

**文件**

- [ ] 确实需要 `fs.write`。如果只是生成一份报告，可以考虑改为发送到一篇笔记。
- [ ] 只写入用户预期的位置（比如在设置中指定的文件夹），绝不覆盖配置文件、锁文件、CI 文件或在构建时会运行的脚本。
- [ ] 重写用户可能正在编辑的文件时使用 `ifMtimeMs`。
- [ ] 除非这就是卡片声明的用途，否则不读取 `.env` 或其他机密文件。

**你展示和发送的数据**

- [ ] 来自外部的文本以文本形式渲染（`textContent`），而不是 HTML（`innerHTML`）。沙箱能挡住最坏的情况，但你的卡片仍然可能被篡改或误导。
- [ ] 端口只发送它的描述所说的内容。
- [ ] 你不根据 `window` 的 `message` 事件行事：任何卡片都能向你的框架发送消息。SDK 的通道是唯一可信的通道。

**打包与更新**

- [ ] `pack --dry-run` 只列出你想发布的内容——没有 `.env`、密钥、私人笔记、`node_modules`，或含真实数据的测试夹具。
（除非你传入 `--allow-secret-files`，否则 `pack` 会拒绝看起来像凭据的文件。）
- [ ] 你的名称和作者没有自称 NeuroSquad、official 或 verified。
- [ ] 你的 GitHub 账号开启了双重验证。任何能推送到你仓库的人，都能给你的用户推送更新。
- [ ] 依赖已锁定（有锁文件），发布前从干净的安装重新构建。
- [ ] 新增权限的变更单独发布，并附上说明。

**行为**

- [ ] 卡片不可见时暂停轮询和动画，并在 `onSuspend` 中保存。
- [ ] 网络轮询频率合理（上限是每分钟 120 个请求——请远低于此）。
- [ ] 某项权限被撤销时，卡片仍能工作——降级处理，并解释原因。

> 发现了卡片突破方框、访问未授权内容，或骗过应用自身对话框的办法？那是 NeuroSquad 的安全漏洞，而不是你卡片的问题——
> 请通过 [Discord 服务器](https://docs.neurosquad.ai/zh/help/faq#discord)私下告知团队，而不要发在公开讨论中。

## 用户会被告知什么

安装对话框会用下面这些话告诉用户：这张卡片是未经 NeuroSquad 审核的社区代码；每项权限在最坏情况下意味着什么
（例如有网络权限时，“anything the card can see may be sent there”——卡片能看到的任何内容都可能被发送到那里）；
以及“anything inside the card is the card's own”——卡片内部的一切都属于卡片本身。
写描述和理由时，要让一个谨慎的用户在读到这些话之后，仍然愿意点同意。
