现在写代码,Claude Code、Codex 这类 AI 辅助开发工具几乎成了标配。工具本身已经很好用,再加上支持安装各种 skill 插件,一个小功能包丢进去就能扩展能力:代码审查、部署脚本、UI 布局美化……你需要什么,插件市场基本都能找到。插件从市场安装;市场也有一套安全机制,代码审核通过后锁定版本,理论上你装的永远是审核过的那一份。

但前段时间安全公司 Air Security 披露的 Plugin4Shell 漏洞证明,当下 skill 的这套机制确实能被绕过。你装好的插件,可以在不知情的情况下被换成恶意代码。这个过程不需要点击,也不需要授权,完全静默运行。Claude Code、Codex、GitHub Copilot、Gemini CLI 这几个常用工具全中招,恰好这些也是大家日常最依赖的开发工具。
不装插件是不是就没事? 是,如果你没装过插件,那可以关掉文章了,这个漏洞和你没什么关系。
插件会自动偷偷安装吗? 不会。安装永远是你主动操作完成的,不存在静默安装插件的情况。
那危险在哪? 在“自动更新”。Claude Code 和 Codex 默认会在后台静默更新已装好的插件;如果插件背后的仓库被攻击者控制、利用,那么恶意版本就会趁着更新被拉到你的机器上。没有弹窗,没有提示,一切都在静悄悄中发生。
怎么判断你的插件有没有风险
不是任何插件都会中招。中招要同时满足两个条件:
1. 插件的源仓库被攻击者控制了。 要么作者本来就是坏人,先发干净的版本攒用户,然后再悄悄动手脚;要么仓库被劫持。安全公司实测披露,925 个插件被劫持,影响 13 万个客户端。
2. 仓库托管在 GitHub 之外。 漏洞利用的是 Git 分支名可以伪装成版本号的特性;GitHub 直接禁止这种分支名,所以仓库在 GitHub 上的插件是安全的。风险主要集中在一些自建 Git 服务器托管的插件。这一点安全团队也实测核查过:官方默认市场里的插件仓库全部在 GitHub 上,如果你是在 GitHub 下载安装的插件,那是没有问题的。
文章末尾给了一段自检代码,可以自行排查一下你当前的环境。
如何入侵的
其实这个过程说起来一点也不复杂。市场锁定插件版本用的是 commit 哈希;工具下载时执行 git checkout <哈希>,但只是校验了这个值,却没有验落盘的代码是不是就是这个哈希。
攻击者在自己控制的仓库里,建一个名字恰好等于锁定哈希的分支,指向恶意代码并设为默认。Git 解析时优先匹配分支名,拉下来的就是恶意代码;工具还报告“锁定校验通过”。再叠加后台自动更新,整条攻击链零点击完成。
恶意代码到你本地之后,就可以以你的权限运行;文件、SSH 密钥、云凭证,在内网环境下,几乎如入无人之境。
解决方式
目前 Claude Code、Codex 已经修复了相关问题,能升级的马上升级;没修复的,需要从可靠仓库安装可靠插件。
按你用的工具对号入座:
| 工具 |
状态 |
动作 |
| Claude Code |
✅ 已修复 |
升级到 2.1.179 及以上,claude --version 查一下 |
| Codex |
✅ 已修复 |
升级到 0.146.0 及以上 |
| GitHub Copilot |
❌ 没有补丁 |
暂时别从第三方市场装插件 |
| Gemini CLI |
❌ 官方不修了 |
迁移到 Google 的 Antigravity |
再补三个动作:
清点插件。 看看自己和团队装了哪些,仓库托管在哪;非 GitHub 托管的重点排查一下,可疑的、不常用的,先卸载掉。
下面是一段 Python 的自检代码,可以根据自己实际的使用情况和使用版本,自查一下:
#!/usr/bin/env python3
# check_plugin_pins.py —— Plugin4Shell 自愈式自查
import subprocess, json, os, sys
# 你的插件根目录(Claude Code 常见路径示例,按实际改,其他工具,就制定成对应的路径)
PLUGIN_ROOT = os.path.expanduser("~/.claude/plugins")
# 期望的 pin 映射:插件名 -> 期望 SHA(从市场记录里自己搬过来)
EXPECTED_PINS = {
"my-audit-skill": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
}
defactual_head(repo: str) -> str:
try:
return subprocess.check_output(
["git", "-C", repo, "rev-parse", "HEAD"],
stderr=subprocess.DEVNULL,
).decode().strip()
except Exception:
return"<unknown>"
defmain():
bad = []
for name, pinned in EXPECTED_PINS.items():
repo = os.path.join(PLUGIN_ROOT, name)
ifnot os.path.isdir(repo):
print(f"[skip] {name} 未安装")
continue
head = actual_head(repo)
ok = head == pinned
flag = "OK "if ok else"BAD"
ifnot ok:
bad.append((name, head))
print(f"[{flag}] {name}: pinned={pinned[:10]}... head={head[:10]}...")
if bad:
print(f"\n发现 {len(bad)} 个插件 HEAD 与 pin 不符,疑似被静默替换!")
sys.exit(1)
print("\n全部插件 HEAD 与 pin 一致。")
if __name__ == "__main__":
main()
团队环境关掉插件静默更新。 个人用户升级到修复版后无所谓;管团队的话,建议给插件更新加一道审批。
收紧凭证。 插件继承你的权限,那就把权限收紧;SSH 私钥、云凭证别裸放开发机。就算哪天被换,损失也有边界。
最后
技术上这不是什么高深漏洞,也不陌生,但信号很明确:AI 插件生态正在重演 npm 链路攻击这类旧剧本。几年前我们学会看好依赖,现在轮到看好 AI 的插件了。这类话题在云栈社区也常被开发者拿来复盘讨论。