正文
AI Agent 要安装依赖时,不要只看它说“项目需要这个包”。你现在要先确认三件事:包名真实存在,来源是可信注册表,安装后不会在你机器或 CI 里执行危险脚本。
这类风险已经不只是传统恶意包。代码模型会把不存在的 npm、PyPI 或 Cargo 包写进建议里,攻击者可以注册这些被模型反复编出来的名字,让开发者在复制命令时装到恶意包。这个方向通常被称为 slopsquatting。参考:The Range Shrinks, the Threat Remains、When LLMs Invent Rust Crates。
install 弹窗先看什么
先看 Agent 到底要执行哪条命令。只要命令会新增依赖、修改 lockfile、运行安装脚本或访问外部 registry,就不要把它当成普通读文件操作。
| 你看到的请求 | 先检查什么 |
|---|---|
npm install <name> | 包名、维护者、下载量、scripts、lockfile 变化 |
pnpm add <name> | 是否符合项目包管理器、是否会改 workspace |
pip install <name> | PyPI 项目是否真实、是否有相似拼写包 |
cargo add <name> | crate 是否真实、版本是否稳定、构建脚本是否存在 |
npx <name> / uvx <name> | 是否会直接执行远程包,不要只看包名 |
如果 Agent 没有展示完整命令和参数,先让它重报一次。命令里出现 curl | sh、npx、postinstall、setup.py、build.rs、全局安装、非官方 registry 或 GitHub tarball 时,默认按高风险处理。
包名是不是 Agent 编出来的
AI 生成的包名看起来常常很合理,但合理不等于真实。比如它可能把命令名当包名,把另一个语言生态里的包名搬过来,或者把真实包多加一个后缀。
允许安装前,先做包名核验:
pnpm view <package-name> name version description repository licensepython -m pip index versions <package-name>cargo search <crate-name> --limit 5成功标准不是“命令能返回东西”这么简单。你还要确认返回的包就是你要用的那个项目,而不是相似拼写、空壳包、刚发布的新包或陌生维护者上传的同名诱饵。
这个依赖真的必须加吗
先让 Agent 说明为什么需要新增依赖。很多时候,它只是为了少写几行代码就引入一个包,或者因为训练数据里常见某个库就默认使用。
可以直接这样问:
先不要安装。请说明:
1. 这次功能是否必须新增依赖
2. 现有依赖或标准库能否完成
3. 如果新增,为什么选择这个包
4. 不新增依赖的实现成本是多少
5. 新增后会改哪些文件和 lockfile如果只是格式化、日期处理、简单请求、字符串转换、少量 CLI 输出解析,优先用现有依赖或标准库。只有当包能明显降低复杂度、减少安全风险或对接明确生态时,再考虑安装。
发布页和仓库对不对得上
不要只看 npm、PyPI 或 crates.io 的名字。继续核对发布页、仓库、维护者和版本时间。
| 检查项 | 可疑信号 |
|---|---|
| 仓库链接 | 没有仓库、链接到无关项目、README 极短 |
| 维护者 | 新账号、维护者突然变更、组织名仿冒 |
| 发布时间 | 刚发布但名字像成熟项目 |
| 下载量 | 极低,且没有明确上游来源 |
| 版本号 | 直接跳到高版本,或和真实项目版本相近 |
| License | 缺失、和仓库不一致 |
如果包名像知名项目,但仓库、维护者或 README 对不上,直接拒绝。不要让 Agent 继续解释“也许这是新包”。新包可以等你人工确认后再装。
安装脚本会不会先跑
依赖安装最危险的地方之一,是脚本会在你还没 import 之前执行。Node 生态里的 preinstall、install、postinstall,Python 生态里的构建步骤,Rust 生态里的 build.rs,都可能在安装或构建阶段运行代码。
Node 项目可以先禁用脚本安装:
pnpm add <package-name> --ignore-scripts如果项目必须使用 npm:
npm install <package-name> --ignore-scripts安装后再检查脚本和包内容。不要在看不清包内容时直接允许脚本运行,尤其是包会读取环境变量、主目录、Git 配置、SSH key、npm token、云厂商凭据或 CI secret 时。
lockfile 里带进了什么
新增一个依赖,lockfile 里可能带进几十个子依赖。Agent 说“只装一个包”,不代表实际只新增一个执行面。
安装前让 Agent 预测影响,安装后看 diff:
git diff -- package.json pnpm-lock.yaml package-lock.json yarn.lock requirements.txt pyproject.toml Cargo.toml Cargo.lock重点看这几类变化:
- 是否新增了和任务无关的大量子依赖。
- 是否改了已有依赖版本。
- 是否替换了 registry、resolved URL 或 integrity。
- 是否带入带脚本的包。
- 是否把 workspace 其它包也改了。
如果 lockfile 改动超过你能在几分钟内看懂的范围,先回退这次依赖变更,让 Agent 给出更小方案。
哪些 install 请求应该拒绝
下面这些请求不需要继续讨论,先拒绝或暂缓:
- 包名查不到,Agent 仍然要求安装。
- 包名像知名库,但维护者和仓库对不上。
- 要求全局安装陌生 CLI。
- 要求执行
npx、uvx或远程脚本,但不给版本和来源。 - 包含 install 脚本,且脚本会联网、读本地配置或执行 shell。
- 要求切换到陌生 registry。
- 要求在 CI、生产机器或含密钥的环境里先试装。
- 为了一个小功能带进大依赖树。
- Agent 不能解释为什么现有依赖不够用。
拒绝之后可以让 Agent 改走无新增依赖方案,或者只输出人工安装说明,不直接执行。
已经装了可疑包怎么办
先停下当前 Agent 会话,不要继续运行测试、构建或脚本。可疑依赖如果已经执行过安装脚本,排查范围要覆盖本地凭据和 CI 环境。
按这个顺序处理:
- 查看 Git diff,确认改了哪些依赖文件。
- 删除可疑依赖和 lockfile 变更。
- 检查安装阶段是否跑过脚本。
- 查最近是否出现异常网络请求、临时文件或新进程。
- 如果包可能读过 token、SSH key、npm token、GitHub token 或云凭据,按泄露处理,轮换凭据。
- 重新用可信依赖或无依赖方案实现。
如果你是在 CI 里装过可疑包,还要检查 CI secret、构建日志、缓存和制品。不要只在本机删掉 node_modules。
项目规则怎么限制新增依赖
把依赖安装规则写进项目规则文件,能让 Agent 在提安装请求前先做自查。规则要短,重点是“新增依赖必须解释、核验、等待确认”。
Dependency policy:
- Auto: inspect package.json, lockfiles, existing dependencies, official docs.
- Ask first: add, remove, upgrade, or run any dependency install command.
- Never: install unknown packages, switch registries, run curl|sh, run npx/uvx for unknown packages, expose tokens.
- Before asking approval, report package name, registry, version, maintainer, repository, scripts, transitive dependency impact, and no-dependency alternative.这段规则不能替代人工审查,但能阻止 Agent 把“新增依赖”伪装成普通实现步骤。
什么时候可以允许安装
可以允许,但要满足可观察条件:
| 条件 | 成功标准 |
|---|---|
| 包名真实 | 官方 registry 能查到,名称和项目一致 |
| 来源可信 | 仓库、维护者、license、发布时间对得上 |
| 版本明确 | 固定具体版本,不随意拉 latest |
| 脚本可控 | install 脚本已检查,必要时先 --ignore-scripts |
| 影响可审 | package 文件和 lockfile diff 可读 |
| 替代方案已比较 | 现有依赖或标准库确实不合适 |
| 验证能跑 | 安装后有测试、构建或最小复现确认 |
真正安全的做法不是永远不装依赖,而是每次安装都能说清楚:为什么需要、装的是谁、会执行什么、带进什么、怎么验证、失败怎么撤回。
结论:安装依赖前先让包名站得住
AI Agent 安装依赖的风险不只来自恶意包,也来自它编出一个看似合理但不存在的包名。只要开发者把命令复制到终端,攻击者就有机会通过相似包名、空壳包、安装脚本或子依赖进入项目。
下一次 Agent 要求安装依赖时,先别点允许。先核对包名、来源、脚本、lockfile 和验证路径。包名站不住,后面的实现都不值得继续。