flawopen.com/AI Security/plugin4shell-ai-agent-plugin-sha-pin-bypass
●
CWE-345 · 高危
安全研究 · FlawOpen
Plugin4Shell:插件 SHA 固定校验绕过
四种 AI 代理插件安装器固定了 Git 修订版,却未校验实际检出的 commit。Plugin4Shell 揭示了这一信任边界缺陷;应检查最终 SHA。[1]
💡 通俗易懂的原理解析 (ELI5)
图书馆按唯一目录号预留某个版本的书。工作人员按这个号码取书,却因为书架标签文字相同而交付了另一本。SHA 固定值就像目录号;安装器必须检查实际检出的 commit,确认一致后才能信任或运行插件。[1]
核心概念与专有名词
Git ref 歧义- Git 将对象 ID 和分支等名称都作为修订表达式处理。在某些情况下,看起来像 commit ID 的名称可能被解析为 ref。[1]
插件市场- 分发代理扩展并记录已审查版本的目录。安装客户端仍须自行强制执行固定校验。[1]
CWE-345- 数据真实性验证不足:系统使用数据前,没有充分确认其是否为预期的真实值。[5]
框架映射
- 本指南所述弱点的 CWE 参考: CWE-345
攻击执行流程分解
源代码对比:漏洞与安全实现
有缺陷的路径把名称解析成功误当成对象身份已验证。补丁将最终 HEAD 与市场记录的固定值比较,并拒绝物化其他 commit。此代码对展示的是 Codex 补丁;其他产品的安装器实现不同,不能假定它们采用了相同修复。[2], [6]
存在漏洞的实现
// OpenAI Codex PR #34644 修复前的代码形态
if let Some(target) = sha.or(ref_name) {
run_git(&["checkout", target], Some(destination))?;
}
// checkout 成功就被当作 SHA 匹配的证明。
加固后的安全修复
// Codex 修复:验证实际解析出的 commit,而不只是请求参数
if let Some(sha) = sha {
run_git(&["checkout", sha], Some(destination))?;
let checked_out_sha =
run_git_output(&["rev-parse", "HEAD"], Some(destination))?;
if !checked_out_sha.eq_ignore_ascii_case(sha) {
return Err(format!(
"checked out Git SHA {checked_out_sha} does not match requested SHA {sha}"
));
}
} else if let Some(ref_name) = ref_name {
run_git(&["checkout", ref_name], Some(destination))?;
}
工程与系统安全加固清单
- ✓每次按 SHA 固定版本执行 checkout 后,都要解析实际检出的 commit(例如 <code>git rev-parse HEAD</code>),并在加载插件文件前与请求的固定值精确比较。[2], [6]
- ✓FlawOpen 实施建议:遇到不匹配、HEAD 缺失、命令错误或修订格式异常时必须失败关闭;不得回退到分支名称。[2]
- ✓使用临时本地仓库测试安装器:让默认分支名与另一个 commit 的 SHA 冲突;确认安装被拒绝且不会加载插件代码。[6]
- ✓FlawOpen 实施建议:在类型和控制流程中区分 ref 名称与不可变 SHA 固定值,并在安装元数据中记录已验证的 commit。[1]
- ✓盘点受影响代理版本和市场使用的 Git 托管平台。GitHub 禁止类似 SHA 的分支名,但该平台规则无法保护其他受支持的托管平台,也不能覆盖报告所述 Gemini 的 FETCH_HEAD 路径。[1], [4]
- ✓引用的 AIR 披露称 Codex 在 0.146.0、Claude Code 在 2.1.179 中修复了问题,但未给出完整的受影响版本范围。对 Copilot 和 Gemini CLI 提出状态判断或行动建议前,请核对厂商最新说明。[1], [3], [7]
- ✓保留 Codex 回归测试
materialize_git_source_rejects_sha_that_resolves_to_hostile_default_branch;它会创建临时本地仓库,并断言在插件源码物化前拒绝不匹配的 HEAD。[6]