一幅生成的抽象插画,置于深石板色场域中:一条长长的水平光带由纤细的淡青色与琥珀色光线构成,从一端延伸到另一端,在靠近中心的一个精确点处断开,一块明亮的琥珀色碎片向上逸出,进入上方空无一物的深色通道;淡淡的同心圆和直尺网格线暗示着一条管线。画面中没有出现文字、人物或组织标识。OrcaRouter 标志合成在右下角。
AI Safety Incidents

Snowflake 的 Jira Token:一个 Copilot 共同署名的缺陷,以及 GitHub 称撰写它的那个人

作者

Gideon Frost

发布日期

最新模型 · 20查看全部模型 →
基准测试:Artificial Analysis · 每日更新
返回全部文章

2026年6月23日,由 Wiz 构建的自主安全智能体 Red Agent 在 Snowflake 拥有的一个公开 GitHub 仓库上提交了一个 issue,并带回了一个凭据。该仓库是 snowflakedb/snowflake-connector-net,而出问题的工作流 .github/workflows/jira_issue.yml 的用途是在任何人提交 issue 时创建 Jira 工单——它将工单标题拼接进 shell 命令,而不是通过环境变量传递,因此一个精心构造的标题在 GitHub Actions 运行器上作为代码执行。Red Agent 取回的令牌以 qa@snowflake.net 身份通过 snowflakecomputing.atlassian.net 进行了认证,并带有对 Snowflake 的工程、安全合规和漏洞赏金 Jira 项目的读取权限。该漏洞已存在五天。Wiz 于 2026年8月17日发布了完整分析。本事件被编目为记录 2026-08-17-snowflake-jira-zhao-dao-can,收录于Orca AI Incident Archive,该档案保存了完整记录集及其置信度评级和引用来源。

插值,以及那个从未运行过的守卫

工作流由 GitHub 事件“issues: opened”触发。任何拥有 GitHub 账户的人都可以通过在公共仓库上提交一个 issue 来触发它——无需邀请、无需维护者角色,也无需 fork。存在漏洞的步骤将 issue 标题读入一个 shell 变量:TITLE=$(echo '${{ github.event.issue.title }}' | sed ...),并使用了两个过滤器,原本意图是在字符串拼接之前转义双引号和单引号。

失败出在操作顺序上,而不是转义上。GitHub 会在 bash 解析脚本文本之前,就把表达式的内容替换到脚本文本中,因此 issue 标题里的单引号会闭合 echo 正在保持打开的带引号字符串。两个 sed 过滤器运行在同一个脚本中,且是在替换之后才运行,所以无法修复已经改变该行解析方式的引号问题。Wiz 的文章明确指出,转义来得太晚,无法阻止突破;而一个精心构造、包含闭合引号和分号的标题,会把攻击者选定的命令追加到运行步骤中。

第二道控制措施本应缩小受众范围,但并未做到。该作业带有一个 if 条件,将 github.event.pull_request.user.login 与 whitesource-for-github-com 机器人的登录名进行比较,显然是为了阻止自动化的依赖拉取请求提交工单。在 issues 事件中根本不存在 pull request 对象,因此该比较针对的是一个 null 属性。The Hacker News 引用的 GitHub 官方文档指出,对不存在的属性进行解引用会求值为空字符串;Wiz 的分析则通过 null 值得出相同结果。无论哪种情况,该条件都会对每个用户求值为 true,而针对该机器人的例外则变成了面向互联网的直通通道。

让这次注入值得上报而非被视为例行问题的,是它所处的环境。同一步骤将 JIRA_BASE_URL、JIRA_USER_EMAIL 和 JIRA_API_TOKEN 作为环境变量持有,因此运行器上的任意命令执行都能触及一份凭据,而不是一片空白基底。未发现任何 Snowflake Connector for .NET 版本受到影响:该弱点存在于仓库的 CI/CD 自动化中,而非已发布的连接器代码中。

Red Agent 拿走了什么,以及它声称丢弃了什么

Wiz 对这次漏洞利用过程的叙述,正是使其有别于扫描器发现的关键所在。第一个 payload 使用了井号字符(#),将 TITLE=$(...) 赋值语句的右括号注释掉了,结果产生了 bash 语法错误,而没有产生回调。该 agent 读取了这一错误,并重写了 payload,用一个分号和一个新的 echo 引号闭合 shell 代码块,随后便收到了带外(out-of-band)回调。该 payload 使用 curl 访问 oast.me 的一个子域名,并携带三个凭据变量的 base64 编码值;回调来自 Azure IP 20.106.182.197,Wiz 将这个地址归属为 GitHub Actions runner。

它返回的令牌是 qa@snowflake.net 的 Jira API 令牌,Wiz 将其影响范围描述为对 Snowflake 的 Atlassian 云实例中工程、安全合规和漏洞赏金跟踪项目的读取访问权限。这就是该档案所记录的危害:不是构建机器上为期五天的代码执行,而是一个可读取工单队列的凭据,这些队列中提交了未修复的工程和安全漏洞——并且据 Wiz 描述,其中还包括漏洞赏金跟踪器。

A self-built HTML card titled 'What the run step could reach', badged 'snowflakedb/snowflake-connector-net · .github/workflows/jira_issue.yml · 18-23 June 2026'. A left panel lists the environment variables held by the step: JIRA_BASE_URL, JIRA_USER_EMAIL, JIRA_API_TOKEN. A right panel reads: identity qa@snowflake.net; Jira host snowflakecomputing.atlassian.net; access, read across engineering, security-compliance and bug-bounty Jira projects. Three tiles read: trigger 'issues: opened'; account required 'any GitHub user'; token rotated '24 June 2026'. A footer cites Wiz Research, published 17 August 2026, and notes no CVE identifier accompanies the flaw.

Wiz表示,已安全删除其在概念验证期间访问的所有内容。Snowflake在给CSO Online的一份声明中表示,该报告“已立即展开调查并予以修复”,并称“我们的调查未发现未经授权访问的证据”;Wiz的博客补充称,Snowflake审查了五天窗口期内的审计日志,发现除Wiz自身的测试地址外,没有第三方使用。Snowflake尚未公布这些日志,因此“不存在其他行为者”的结论依据的是其说法以及Wiz对此的总结,而不是两家组织之外任何人都能阅读的文件。

谁写了那行有漏洞的代码

那个问题引出了第二个、更大的故事。PR #1218 标题为“SNOW-2069227: Update jira workflows”,于 2026 年 6 月 18 日以压缩合并方式合并为提交 4a1b8ce,而该压缩提交将“Copilot Autofix powered by AI”列为其共同作者之一。Wiz 最初的标题恰恰依赖这一点,将该漏洞描述为存在于一个由 GitHub Copilot 辅助的拉取请求中,早期行业媒体报道也沿用了同一口径——SC Media 的标题写道:“Wiz 代理在由 GitHub Copilot Autofix 共同编写的代码中发现 Snowflake 仓库漏洞”。

GitHub 的立场是:据 The Next Web 报道,并在 Cloud Security Alliance 的一份研究简报中概述,其内部审查发现“导致该漏洞的贡献是由人类编写的”,而 Copilot Autofix“既未审查也未参与其中”。这一反驳的技术依据在于 git 历史。压缩合并(squash merge)会将一个拉取请求折叠为单个提交,并会将每个共同作者尾注一并带入,无论该作者实际改动了哪些行;因此,共同作者行记录的是对拉取请求的参与,而不是对某个特定差异块(hunk)的作者身份。Copilot 在同一拉取请求中的共同署名提交 6d0e2fa 修改了 jira_close.yml——这是一个与存在漏洞的 jira_issue.yml 不同的工作流。不安全的插值被归因于提交 094038e,日期为 2025 年 8 月 25 日,GitHub 将其归因于 Snowflake 工程师 sfc-gh-hpathak;PR #1218 于 2026 年 6 月将该模式带入默认分支。

Wiz 并未撤回该漏洞发现,并在发布当天改变了叙事框架。其博客上有一篇发布于 8 月 17 日 19:57 UTC 的更新,将 Copilot 描述为“一个检查了已合并 PR 和代码变更的共同作者”,它“认定一切正常”,却没有注意到这些漏洞,并承认“尚不清楚该代码变更是否由 AI 辅助完成”。在这种说法中,AI 的失误属于审查层面的失误,而非作者身份层面的失误:已合并的拉取请求带有 Copilot 的共同签名,而注入仍然通过了审查。CSO Online 引用 Wiz CTO Ami Luttwak 的话说,在人类与 AI 之间进行清晰归因“正变得有点更难确定”,而且“仅看 PR 的共同作者是不够的”。

A self-built HTML card titled 'Two accounts of one commit', badged 'PR #1218 · SNOW-2069227 · squash-merged 18 June 2026 as commit 4a1b8ce'. A cyan-headed left panel, 'GitHub, internal review', reads: a human wrote the contributions that led to the vulnerability; Copilot Autofix neither reviewed nor contributed to them; Copilot's co-authored commit 6d0e2fa changed jira_close.yml, not the vulnerable file; the unsafe pattern traces to commit 094038e of 25 August 2025; squash-merging carries each co-author trailer forward regardless of which lines that author touched. An amber-headed right panel, 'Wiz, blog update, 17 August 2026, 19:57 UTC', reads: Copilot was a co-author that checked the merged PR and code change; it identified it as all-clear without noticing the vulnerabilities; it is unclear whether the code-change was AI-assisted; Copilot Autofix is listed among the squash commit's co-authors; the post was revised on the evening of publication without retracting the finding. Below, an open-question strip asks whether Copilot reviewed jira_issue.yml inside PR #1218, and a dashed band lists what is not in dispute.

两份说法中一致的部分,值得与它们争执的部分区分开来。双方都同意,该 squash 提交带有 Copilot Autofix 的共同作者尾注,并且该工作流可被利用。双方也都不否认,GitHub Advanced Security 扫描了拉取请求的最终修订版,提取了 jira_issue.yml,却没有标记该注入——Wiz 将其报告为一次漏报,而 GitHub 的反驳针对的是作者归属,而非扫描本身。仍未解决的是,Copilot 究竟是否审查过这些易受攻击的代码行:Wiz 称进行了一次审查并让它们通过了,GitHub 称该工具与这些代码行毫无关系,而能定论的日志掌握在这两家公司之一手中。记录同时保留双方说法,而非做出选择。

五天,以及之后发生了什么变化

修复在报告提交后很快就完成了。Wiz 于 6 月 23 日通过 Snowflake 的 HackerOne 项目提交了报告 #3819931,并于同日通过 Slack 通知了 Snowflake 安全团队;Snowflake 合并了 PR #1402(提交 1dc7766),该变更将直接表达式展开替换为作为参数传给 jq 的环境变量。Wiz 的时间线将 Jira 令牌轮换定在 6 月 24 日,而 The Hacker News 也报道了同样的时间区分。相比之下,Wiz 自己的介绍称 Snowflake “在同一天”修复了漏洞并轮换了凭据——这是主要来源内部的一处矛盾,记录不应加以掩盖。修复于 6 月 23 日落地;在 Wiz 的表格中,轮换日期为 6 月 24 日。

披露时间表由 Snowflake 掌控:Wiz 将公开披露截止日期定为 2026 年 7 月 25 日,即根据该计划政策于 6 月 25 日完成处置后的三十天,并于 8 月 17 日发布了分析。Snowflake 向 CSO Online 发表的声明称,该公司“感谢 Wiz 负责任的报告”,并正与 Wiz 合作,将这些经验教训分享给业界。无论是 Wiz 的分析还是 The Hacker News 的报道,均未包含 CVE 标识符、CVSS 评分,也未出现在 CISA 的已知被利用漏洞目录中;该缺陷是公共代码仓库中的一项工作流配置,而不是已发布的库,因此它从未以常规方式进入漏洞数据库。

A self-built HTML card titled 'Five days live, five weeks to publication', subtitled 'Every date below is day-precision, as reported by Wiz Research and The Hacker News'. A vertical timeline lists six entries: 25 August 2025, commit 094038e introduces the unsafe jira_issue.yml refactor, attributed by GitHub to a Snowflake engineer; 18 June 2026, PR #1218 squash-merged as 4a1b8ce and the flaw goes live on the default branch; 23 June 2026, Wiz reports via HackerOne #3819931 and Snowflake merges fix PR #1402 as 1dc7766; 24 June 2026, Jira API token rotated, the fix having landed a day earlier; 25 July 2026, public disclosure deadline under Snowflake's HackerOne policy; 17 August 2026, Wiz publishes the full analysis, blog updated at 19:57 UTC. An amber band reads 'Exposure window: five days, 18 to 23 June 2026'. A footer notes no CVE identifier, CVSS score or known-exploited entry accompanies the record.

记录确立了什么,以及没有确立什么

该档案将此归类为研究成果而非部署事件,严重性为高,置信度等级为 A,确认涉及 AI,且记录了真实危害;其日期为 2026 年 8 月 17 日,即 Wiz 发布之日,而事件本身跨 6 月 18 日至 23 日。已确立的核心范围狭窄且可核查:一个公开工作流将攻击者控制的文本插入 shell 命令,其防护条件与该事件中为 null 的属性进行比较,同一操作步骤中存在一个 Jira 令牌,一个自主智能体利用了这一点,Snowflake 在一天内合并了修复并轮换了该凭据。

那些属于推断而非记录的部分,正是随意转述往往会被抹平的地方。Copilot Autofix 被记录为该拉取请求的合著者,而没有被记录为存在漏洞的代码行的作者;支撑首轮新闻报道的“AI 对 AI”叙事框架,被报道机构在数小时内部分撤回,并遭到 GitHub 反驳。该已合并拉取请求的 AI 审查是否查看了 jira_issue.yml,仍是一个悬而未决的事实问题,而非已有定论。至于访问范围,尽管 Wiz 作了详细描述,却尚未经过独立审计:没有任何 Jira 权限、工作流运行或审计记录被公开。

这种修复模式正是 GitHub 自己的指南自 2025 年 7 月以来一直推荐的——将不受信任的 issue 数据传入环境变量,并作为参数交给 jq,而不是在 run 块内展开它。Snowflake 合并的提交正是这样做的,修正后的处理仍保留在默认分支上。对于任何将该记录视为先例的人来说,持久的发现关乎归属而非注入:当一个拉取请求包含多个人类和多个代理时,共同作者尾注无法告诉你某一行是谁写的,而 Wiz 和 GitHub 最终用不同措辞都说明了这一点。