
Snowflake 的 Jira Token:一个 Copilot 共同署名的缺陷,以及 GitHub 称撰写它的那个人
- Orca新OrcaCyber: MiniMax M3.1 Flash Abliterated2026-10-29orca/orcacyber-minimax-m3.1-flash
- Orca新OrcaCyber: GLM 5.3 Flash Abliterated2026-10-2793 tok/s
- Orca新OrcaCyber: Qwen3.8 Flash Next Abliterated2026-10-26$0.80 / $1.60 每百万 tokens · 260 tok/s
- Orca新OrcaCyber: MiMo V2.6 Flash Abliterated2026-10-26$0.80 / $1.60 每百万 tokens · 92 tok/s
- Moonshot新MoonshotAI: Kimi K3.1 Pro2026-10-2446智能
- Orca新OrcaCyber: DeepSeek V4.1 Flash Abliterated2026-10-23$0.80 / $1.60 每百万 tokens · 104 tok/s
- minimax新MiniMax: M3.1 Flash2026-10-1929智能
- Orca新Orca: OrcaCyber Ultra 1.02026-10-17$5.00 / $10.00 每百万 tokens · 65 tok/s
- deepseek新DeepSeek: DeepSeek V4.1 Flash 10172026-10-1733智能
- DeepSeek新DeepSeek: DeepSeek V4.1 Flash2026-10-1740智能
- OrcaOrca: OrcaCyber Zero 1.52026-10-10$3.00 / $7.50 每百万 tokens · 101 tok/s
- openaiOpenAI: GPT-6.1 Sol2026-09-2955智能
- anthropicAnthropic: Claude Sonnet 5.52026-09-2854智能
- typesafeTypeSafe: Jev 1.132026-09-24$0.04 / $0.00 每百万 tokens · 180 tok/s
- OpenAIOpenAI: GPT-6 Luna2026-09-2228智能
- OpenAIOpenAI: GPT-6 Sol2026-09-2248智能
- AnthropicAnthropic: Claude Opus 5.52026-09-2258智能
- xiaomiXiaomi: MiMo-V2.6-Flash2026-09-2127智能
- xiaomiXiaomi: MiMo-V2.6-Pro2026-09-2130智能
- xAIGrok 4.72026-09-2134智能
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 描述,其中还包括漏洞赏金跟踪器。

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 的共同作者是不够的”。

两份说法中一致的部分,值得与它们争执的部分区分开来。双方都同意,该 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,确认涉及 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 最终用不同措辞都说明了这一点。
