1. 当 Coding Agent 开始“编”依赖:Slopsquatting 是怎么发生的
LLM Coding Agent 最危险的地方,不是它写错一行语法,而是它用非常自信的语气,让你安装一个根本不存在的包。这个现象叫 Package Hallucination,攻击方式叫 Slopsquatting:模型补全依赖时凭空造出一个包名,攻击者提前把这个名字注册到 PyPI 或 npm,你一条pip install就把恶意代码拉进了依赖链。
它和传统的 typosquatting 不一样。typosquatting 赌的是人手滑打错字,Slopsquatting 赌的是你信任模型。Cline、Cursor、Continue 这类工具在补全requirements.txt、package.json或直接给安装命令时,经常出现“看起来很像真的”的包名,比如把requests写成request、把某个内部库名拼成一个公开仓库里不存在的名字。你如果直接回车执行,供应链攻击就完成了。
这篇文章聚焦一个可复现的本地场景:用 Cline/Cursor 类 Agent 生成依赖,通过 TaoToken 统一 Key 和 API 通道接入模型,然后给出包名核验与依赖锁定的验证动作。适合正在用 Coding Agent 写代码、又想把依赖风险控制住的开发者。下面所有配置都可以直接复制,重点是让你看到“模型建议的包”和“真实存在的包”之间那道必须自己补上的校验。
2. 前置准备:用 TaoToken 统一 Key 接入 Coding Agent
Coding Agent 的依赖幻觉,和你用哪个模型通道关系不大,但统一通道能让复现和排查更干净。TaoToken 在这里的角色是提供一个统一的 API 入口,你不需要在 Cline、Cursor、脚本里分别维护多套 Key,模型对话、编码补全、Agent 调用都走同一个通道,出问题时也容易定位是模型输出还是本地配置的问题。
先拿到 Key。打开 https://taotoken.net/api-keys 创建 API Key,注意这个 Key 只显示一次,复制后放到本地环境变量里,不要写进会提交到 Git 的配置文件。接入文档在 https://taotoken.net/doc ,里面有各客户端的字段说明。如果你只是想先验证模型会不会编包名,可以直接用模型对话页面 https://taotoken.net/models 做几轮测试,不用先配 Agent。
TaoToken 的 API 基址是https://taotoken.net/api,兼容 OpenAI 风格的chat/completions。Cline 这类工具通常要求填 Base URL 和 API Key,Base URL 填https://taotoken.net/api,Key 填你刚创建的那串。长期跑编码任务、Agent 频繁调用的话,可以看下 Coding Plan https://taotoken.net/coding-plan ,它更适合这种持续补全和工具调用的场景,普通按量调用用 API Key 就够了。
这里要强调一个边界:TaoToken 是模型接入通道,不是包管理器,也不是安全扫描器。它能帮你统一 Key、稳定拿到模型输出,但“这个包到底存不存在”必须由你在本地或 CI 里核验。把安全校验交给模型自己,等于把门锁交给小偷保管。
3. 可复制配置:settings.json 与 config.toml 骨架
下面给两份骨架。第一份是 Cline 类 VS Code 插件的settings.json,第二份是通用 Agent 的config.toml。字段名按你实际用的工具微调,核心是 Base URL、Key 来源和模型名。
{ "cline.apiProvider": "openai", "cline.openAiBaseUrl": "https://taotoken.net/api", "cline.openAiApiKey": "${env:TAOTOKEN_API_KEY}", "cline.openAiModelId": "gpt-4o-mini", "cline.enableAutoApprove": false, "cline.autoApproveReadOnly": true, "cline.autoApproveWrite": false, "cline.autoApproveExecute": false }关键点有三个。openAiBaseUrl指向 TaoToken 的 API 地址,不要多加斜杠或路径。openAiApiKey用环境变量引用,避免明文进仓库。enableAutoApprove和几个autoApprove*全部关掉执行权限,尤其是autoApproveExecute,否则 Agent 可能直接帮你跑pip install,把幻觉包名变成真实安装。
[provider] name = "taotoken" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" model = "gpt-4o-mini" timeout_seconds = 60 [agent] auto_execute = false confirm_shell = true max_tool_calls = 20 [dependency_guard] verify_before_install = true allow_registries = ["pypi", "npm"] lockfile_required = true[dependency_guard]这一段不是所有工具原生支持,但你可以把它当成自己的约定:任何安装动作前先核验,只允许 PyPI 和 npm 两个来源,必须生成 lockfile。如果你的 Agent 不支持这些字段,就在外层包一个脚本,拦截pip install和npm install命令,先查包再放行。
环境变量这样设,Linux/macOS 写进~/.zshrc或~/.bashrc,Windows 用系统环境变量:
export TAOTOKEN_API_KEY="sk-你的Key"设完source ~/.zshrc,然后在 Cline 里发一条测试消息,确认能正常返回,再进入下一步。
4. 验证请求:让 Agent 生成依赖并核验包名
先制造一次“幻觉现场”。在 Cline 里输入一个容易触发编造包名的任务,比如“用 Python 写一个读取 PDF 表格并导出 Excel 的脚本,给出完整依赖”。模型很可能给出pdfplumber、pandas、openpyxl这类真实包,也可能混进一个不存在的名字。把它的输出记下来,重点看pip install后面的包名。
然后用脚本核验。下面这段 Python 会拿包名去 PyPI 查询,不存在就标红。它不依赖模型,只依赖官方仓库。
import sys import urllib.request import json def check_pypi(pkg: str) -> bool: url = f"https://pypi.org/pypi/{pkg}/json" try: with urllib.request.urlopen(url, timeout=10) as resp: return resp.status == 200 except Exception: return False if __name__ == "__main__": for name in sys.argv[1:]: ok = check_pypi(name) print(f"{name}: {'OK' if ok else 'NOT FOUND'}")跑一下:
python check_pkg.py pdfplumber pandas openpyxl fake-package-name输出里fake-package-name: NOT FOUND就是幻觉包名。npm 同理,把 URL 换成https://registry.npmjs.org/{pkg},返回 200 即存在。这一步是整篇文章最该固化的动作:模型给依赖,脚本查仓库,人做决定。
再验证一次模型通道是否稳定。用 curl 直接打 TaoToken 的接口,确认返回正常:
curl https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "列出 Python 读取 Excel 常用的三个真实存在的包名"}] }'如果返回里出现你不认识的包名,别急着装,先过一遍上面的核验脚本。成功的结果不是“模型答得漂亮”,而是“模型给的每个包都能在官方仓库查到,且 lockfile 里版本被钉死”。
5. 本篇常见错排查
第一个坑是 Base URL 写错。有人填https://taotoken.net/api/v1或漏掉/api,Cline 报 404 或连接失败。正确写法是https://taotoken.net/api,路径由客户端自己拼。如果报 401,检查 Key 是否带上了Bearer前缀,以及环境变量有没有真正生效,echo $TAOTOKEN_API_KEY看一眼。
第二个坑是自动执行没关。Agent 在补全requirements.txt后直接触发安装,你还没核验就装完了。回到settings.json,把autoApproveExecute设为false,confirmShell设为true。这一步比换模型重要得多,因为再强的模型也会偶发幻觉,而执行权限一旦放开,幻觉就直接落地。
第三个坑是只查 import 不查 package。Python 里import PIL对应的包是Pillow,import cv2对应opencv-python,module 名和 package 名不是一一对应。你如果拿 import 语句去 PyPI 查,会误判。核验时以pip install后面的名字为准,或者让模型明确列出“要安装的包名”而不是“要导入的模块名”。
第四个坑是 lockfile 缺失。没有requirements.txt的精确版本或package-lock.json,下次安装可能拉到被攻击者替换的版本。生成 lockfile 后提交到仓库,CI 里用pip install -r requirements.txt --require-hashes或npm ci,把依赖钉死。
第五个坑是以为“包存在就安全”。Slopsquatting 的变种是攻击者注册一个真实存在但恶意的包,名字和幻觉名一致。所以核验存在只是第一层,还要看下载量、维护者、发布时间。新注册、零下载、名字又很“通用”的包,直接跳过。
6. 把统一 Key 和依赖核验接进你的日常流程
复现到这里,链路已经清楚了:Agent 生成依赖,TaoToken 提供稳定的模型通道,核验脚本查官方仓库,lockfile 锁定版本。真正要固化的是顺序,先核验再安装,先锁版本再提交。你可以把核验脚本挂到 pre-commit 钩子里,任何新增依赖都先过一遍 PyPI/npm 查询,查不到就拒绝提交。
如果你还在调 Agent 的接入配置,先去 https://taotoken.net/api-keys 把 Key 建好,字段说明看 https://taotoken.net/doc ,想先观察模型会不会编包名就用 https://taotoken.net/models 做几轮对话测试。长期跑编码和 Agent 任务的话,https://taotoken.net/coding-plan 比按量调用更省心。记住一句话:模型可以帮你写代码,但依赖是否真实存在,永远由你的核验脚本说了算。