news 2026/9/17 6:17:53

pull_request_target 与 PR Head 检出:AI Agent 工作流提示注入攻击向量(Vector D)深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pull_request_target 与 PR Head 检出:AI Agent 工作流提示注入攻击向量(Vector D)深度解析

pull_request_target 与 PR Head 检出:AI Agent 工作流提示注入攻击向量(Vector D)深度解析

【免费下载链接】anomalibAn anomaly detection library comprising state-of-the-art algorithms and features such as experiment management, hyper-parameter optimization, and edge inference.项目地址: https://gitcode.com/GitHub_Trending/an/anomalib

导读

本文基于 anomalib 仓库内agentic-actions-auditor技能库的 Vector D 参考文档,深入剖析一类针对 CI/CD 中 AI Agent(Claude Code Action、Gemini CLI、OpenAI Codex 等)的高危提示注入攻击:当工作流使用pull_request_target触发,并检出 PR 的 head 提交时,攻击者的代码将携带仓库机密(Secrets)进入 AI Agent 的执行上下文。读完本文,你将掌握该向量的完整数据流、两步检测法、漏洞模式示例、误报排除规则与可落地的加固修复方案。

攻击向量概述:可信执行上下文 × 不可信代码

pull_request_target是 GitHub Actions 中一个特殊且高危的触发事件:它运行的是基础分支(base branch)上的工作流定义,而非来自 Fork 的 PR 分支定义。这意味着工作流拥有仓库机密的访问权限,同时却能被任何外部贡献者通过提交 Pull Request 触发。

当工作流在pull_request_target上下文中执行actions/checkout并显式检出 PR 的 head 提交(${{ github.event.pull_request.head.sha }}等)时,就形成了 Vector D 的核心条件:

可信执行上下文(携带 Secrets)+ 攻击者控制的代码(PR head)

AI Agent 在拥有仓库 Secrets 的进程里,读取的是攻击者修改过的文件(代码注释、README、配置文件、测试文件、文档等)。攻击者在这些文件中埋入提示注入载荷,AI 一旦读取并"听从",就会以持有 Secrets 的 Agent 身份执行攻击者指令。

适用 Action:凡是"从工作目录读文件"的 AI 都有风险

该向量的关键前提是:AI Action 会从检出(checked-out)的工作目录读取文件。因此,只要被调用的 AI 工具具备文件系统读取能力,就适用此向量。文档给出的适用性对照如下:

Action适用性说明
Claude Code Action适用(已确认)PoC 18 已验证;会读取检出的工作目录文件
Gemini CLI适用若配合pull_request_target使用,文件系统读取行为相同
OpenAI Codex适用会读取工作目录文件用于代码分析
GitHub AI Inference可能较少见,但当提示词指示模型从磁盘读取文件内容时同样适用

攻击者将提示注入载荷(prompt injection payload)嵌入代码注释、README 文件、配置文件,或任何 AI 在评审过程中可能读取的文件中——AI 评审的正是这些文件本身,因此注入面天然存在。

触发事件:为什么是 pull_request_target

  • pull_request_target:工作流从基础分支运行(拥有仓库 Secrets),但由外部 Pull Request 激活。这一"信任"与"不可信输入"的组合正是漏洞根源。
  • 普通pull_request:来自 Fork 的 PR不会获得仓库 Secrets,因此从 Secrets 窃取角度看是安全的(虽然代码执行在其他场景下仍是隐患)。

这一点在技能库的 foundations.md 中有完整的触发事件风险对照表:pull_request_target暴露的攻击者可控数据包括 PR 标题、正文、head ref 与 head SHA,且运行于带 Secrets 的基础分支上下文,风险等级最高。

数据流:从攻击者 PR 到 AI 执行上下文

Attacker opens fork PR -> pull_request_target runs workflow from base branch (has secrets) -> actions/checkout with ref: PR head fetches attacker's code to disk -> AI agent reads files from working directory -> Attacker-modified code processed with access to repository secrets

这条链路的关键点在foundations.md的三条数据流模型(Path 1 直接表达式插值、Path 2 env 变量中转、Path 3 运行时拉取)之外构成第四种形态:攻击者输入经由"文件系统"这一物理媒介进入 AI 上下文。与 Vector C(CLI 数据拉取)类似,工作流 YAML 本身可能看起来非常"干净"——没有任何${{ github.event.* }}出现在 prompt 字段中,因为恶意内容存在于磁盘文件中,而非事件上下文字符串。

两步检测法:两个条件必须同时成立

检测 Vector D 必须遵循两步走,缺一不可

第一步:检查on:块中是否存在pull_request_target触发事件

第二步:查找检出 PR head 的 checkout 步骤,命中以下任一模式即触发告警:

  • actions/checkout(任意版本)带ref:,且取值为以下之一:
    • ${{ github.event.pull_request.head.sha }}
    • ${{ github.event.pull_request.head.ref }}
    • ${{ github.head_ref }}
  • run:步骤中的git checkout/git fetch命令拉取 PR head 分支或提交

pull_request_target单独出现不是漏洞。没有检出 PR head,AI Agent 只会看到可信的基础分支代码;是"检出"这一步让代码落入攻击者控制。这就是为何该向量在技能库的 SKILL.md 中被标记为 "PR Target + Checkout"(快速检查:pull_request_target触发 + 带指向 PR head 的ref:的 checkout)。

排查位置清单

  1. 工作流文件顶部的on:块:查找pull_request_target
  2. 所有 job 中的所有steps::查找带ref:with.ref字段的actions/checkout步骤
  3. run:步骤中的git checkoutgit fetchgit switch命令,确认是否引用 PR head
  4. 注意:不带ref:字段的actions/checkout默认检出基础分支,在pull_request_target下是安全的

从技能库的 cross-file-resolution.md 可知,这类 AI Agent 还可能隐藏在被调用的复合动作(composite action)或可复用工作流(reusable workflow)中——审计时应沿uses:引用做一层深度解析,并追踪with:inputs.*→ prompt 字段的输入映射链路。

为什么危险:Secrets 与攻击者文件的结合

AI Agent 运行时所处的执行上下文携带基础分支 Secrets,可能包括:

  • 具备写权限的GITHUB_TOKEN
  • 部署密钥(deployment keys)
  • API 凭证
  • 仓库中配置的任何其他 Secrets

但它处理的却是攻击者修改过的文件。攻击者可以在 AI 大概率会读取的任何文件中埋入提示注入载荷:代码注释、README、配置文件、测试文件、文档。一旦注入成功,AI 将带着这些 Secrets 执行攻击者指令

foundations.md还补充了一个易被忽略的机制:env:块中的${{ }}表达式在步骤运行之前就被求值,步骤只能看到解析后的字符串值。这意味着即使审计人员未在 prompt 字段中发现表达式,攻击者内容也可能经 env 变量中转进入 AI 上下文(即 Vector A),与本向量叠加放大风险。

漏洞模式示例(来自 PoC 18)

以下 YAML 来自 PoC 18(frankbria/ralph-claude-code),完整展示了两个步骤的配合:

on: pull_request_target: # Step 1: Runs in base branch context types: [opened, synchronize] jobs: claude-review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} # Step 2: Checks out ATTACKER's code - uses: anthropics/claude-code-action@v1 with: prompt: | Please review this pull request and provide feedback # AI reads attacker-modified files from disk with base repo secrets available

Step 1 使工作流在基础分支上下文运行(获得 Secrets);Step 2 把攻击者的代码检出到磁盘;随后 Claude Code Action 以"请评审这个 PR"的善意提示启动,但实际读取的代码、README 与配置文件中都可能是攻击者精心构造的注入指令。

误报排除:五类常见安全场景

为避免安全团队被误报淹没,文档明确列出以下安全场景(最常被误报):

  • pull_request_target但未检出 PR head:AI 只能看到可信的基础分支代码——这是最常见的误报来源
  • pull_request_target+actions/checkout但无ref:字段:默认检出基础分支,安全
  • 普通pull_request触发 + 检出 PR head:Fork 的 PR 不获得 Secrets,无法实现机密窃取(虽然 runner 上的代码执行仍是独立隐患)
  • pull_request_target仅用于打标签、评论或状态检查,且没有在代码上运行 AI Agent:无 AI 处理即无提示注入面
  • pull_request_targetref:显式指向基础分支(如ref: ${{ github.event.pull_request.base.sha }}):检出的是可信代码

修复与加固建议

结合技能库 action-profiles.md 中各 Action 的安全配置基线,修复方向分为两类:

根治检出问题(直接消除向量 D):

  • 优先使用pull_request触发 + 手动批准后运行,或对来自 Fork 的 PR 不检出 head(默认检出基础分支)
  • 若必须评审 PR head,先人工审核或使用隔离环境,确保 AI Agent 与仓库 Secrets 不在同一执行上下文
  • 在检出后增加内容消毒步骤(去除 HTML 注释、不可见字符、Markdown 图片 alt 文本等隐藏注入载体),这与 Claude Code Action 内置的 prompt 清洗逻辑思路一致

纵深防御(降低注入成功后的影响):

Action推荐加固
Claude Code Action--allowedTools "Bash(npm test:*) Bash(git diff:*)"替代Bash(*);保持show_full_output: false;不使用allowed_non_write_users: "*"
OpenAI Codexsandbox: workspace-write(默认)或read-onlysafety-strategy: drop-sudoallow-users用显式用户列表
Gemini CLIsettings JSON 中配置"sandbox": true;移除--yolotools.core中不放run_shell_command(echo)等可扩展命令
通用最小化permissions:(如contents: read);AI 输出绝不经eval/exec/未加引号的$()消费(Vector G)

需要特别强调:从本仓库.github/workflows/的实际扫描结果看,现有的auto-approve.yml等文件虽引用了github.event.pull_request.head.sha,但当前仓库工作流中并未发现pull_request_target+ 检出 PR head 的组合,也未发现 AI Action 调用——即本仓库当前不构成 Vector D 的实际利用面,本文所分析的场景适用于"将来或他处引入 AI Agent 工作流"时的防御基线。

结语:把"检出 PR head"当作代码执行边界来审查

Vector D 的本质是信任边界混淆pull_request_target提供了可信执行上下文(Secrets),而检出 PR head 把不可信代码引入该上下文。审计 CI/CD 中的 AI Agent 集成时,应把"是否检出攻击者控制的代码"视为与"是否执行攻击者脚本"同级的代码执行边界问题。掌握本文的两步检测法与误报排除规则后,即可在引入 Claude Code Action、Gemini CLI 或 OpenAI Codex 等工作流时,快速识别并阻断这一高危注入路径。

【免费下载链接】anomalibAn anomaly detection library comprising state-of-the-art algorithms and features such as experiment management, hyper-parameter optimization, and edge inference.项目地址: https://gitcode.com/GitHub_Trending/an/anomalib

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 6:17:40

一人成团做漫剧:豆包、即梦、剪映、扣子AI流水线实战指南

普通人一人成团做漫剧:把豆包、即梦、剪映、扣子串成一条AI流水线后台一直有人问我,漫剧到底是不是智商税?一个人到底能不能做?我的回答一直是:能,但前提是你别把四个工具当成四个孤岛,而是当成…

作者头像 李华
网站建设 2026/9/17 6:15:50

CT重建中的等角扇束到平行束重排:MATLAB实现与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 6:15:21

四颗工业级芯片选型实战:精度、可靠与合规的硬核解剖

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 6:15:01

安庆近视手术好的医院有哪些?技术参数与口碑多维度解析

医护人员做近视手术,有一个天然优势:比普通人群更懂"什么才算靠谱"。设备型号、检查流程、感控标准、医生资质,这些信息在同行眼里都是可以逐项核对的硬指标——不需要听宣传话术,自己就能判断。安庆的医护同行如果决定…

作者头像 李华
网站建设 2026/9/17 6:12:06

10MB的Postman替代品,秒开轻量级API调试工具实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华