正在刊行长文 · Essay
2026-07-09所有内容
随机比特 · Random Bits

一个 GitHub Issue,就能让 AI Agent 吐出私有仓库

2026-07-09AI Engineering / Systemsrbits.uk
一个 GitHub Issue,就能让 AI Agent 吐出私有仓库

攻击者没有拿到 GitHub Token,也没有进入目标组织的私有仓库。

他只是打开一个公开仓库,提交了一个 Issue。

Issue 写得很正常:销售负责人刚见完客户,希望团队整理几个仓库的信息,用来准备后续沟通。没有恶意链接,没有奇怪脚本,也没有电影里那种一眼可疑的黑客口吻。

接下来,自动化开始工作。Issue 被分配,工作流触发,AI Agent 读取这段需求,访问组织内的公开仓库和私有仓库,最后把读取到的 README 内容写进了公开 Issue 的评论区。

这就是 Noma Labs 研究者 Sasi Levi 在 7 月 6 日披露的 GitLost 演示。

它不是“GitHub 全平台被攻破”。演示成立需要一类特定配置:公开输入能触发 Agent,Agent 拥有跨仓库读取权限,同时又能向公开位置输出内容。

但这个场景足够刺眼。因为很多团队正在把 Coding Agent 接进私仓、CI、工单和知识库。过去我们问的是:这个 Agent 会不会写错代码。现在更该问的是:它听谁的话,能读什么,最后能把结果发到哪里。

正常流程中的权限错位

GitHub Agentic Workflows 在 6 月 11 日进入 public preview。开发者可以用自然语言 Markdown 描述工作流,再编译成标准 GitHub Actions YAML。官方给出的场景包括 Issue 分类、CI 失败分析和文档更新。

这类能力很容易让工程团队心动。传统 Actions 只能按脚本执行,Agent 能读上下文、理解意图、调用工具,还能根据结果决定下一步。比如 GitHub Blog 7 月 8 日介绍的跨仓库文档工作流:产品代码合并后,Agent 读取代码和关联 Issue,在文档仓库生成草稿 PR,再交给负责人审核。

这确实是工程效率的方向。问题也恰好在这里。

为了让 Agent 有用,我们会给它更多上下文、更多工具和更多仓库权限。为了让协作顺畅,我们还会让它评论 Issue、创建 PR、写日志、发通知。每一项单独看都合理,连在一起就可能变成数据出口。

GitHub 当然不是没有安全设计。官方公开资料提到默认只读、沙箱容器、Agent Workflow Firewall、safe outputs 和 threat detection。安全架构文章也明确把 Agent 当成不能默认信任的组件,不让它直接接触 secrets,并要求检查写操作。

GitLost 真正提醒的是:安全设计不能替工作流作者决定边界。哪些输入可以驱动 Agent,哪些仓库可以被读取,哪些结果可以公开输出,仍然是工程配置问题。

外泄链路如何形成

根据 Noma 的披露,演示中的工作流由 issues.assigned 事件触发。它会读取 Issue 标题和正文,可以用 add-comment 回复,并拥有读取同一组织内其他公开、私有仓库的权限。

攻击者没有绕过 GitHub 的私仓鉴权。他做的是另一件事:影响一个本来就有权限的执行者。

第一步,是投递不可信输入。研究者创建一个公开 Issue,把请求包装成销售 VP 会见客户后的资料整理任务。对普通程序来说,Issue 正文只是数据;对 Agent 来说,它可能同时变成任务指令。

第二步,是借用 Agent 的合法权限。工作流启动后,Agent 按照 Issue 内容,从公开仓库和私有仓库读取 README。私仓没有被“破解”,内容是被一个有读取权的 Agent 取出来的。

第三步,是借用合法输出通道。Agent 把读取到的内容写进公开 Issue comment。至此,每一步都像是被允许的操作,组合结果却是私有数据公开。

公开 Issue 到私仓外泄链路

原文还提到,GitHub 已经设置 guardrails。研究者在测试不同表达时加入 “Additionally”,观察到模型出现非预期行为,重新组织输出而没有拒绝请求。这个细节不能被理解成一个通用绕过词。真正可复用的判断来自三段链路本身:输入是否不可信,权限是否能读敏感数据,输出是否对外可见。

只读权限保护不了机密性

很多团队看到“默认只读”会松一口气。对传统 CI 来说,这通常意味着不能改代码、不能部署、不能删除东西,风险似乎小很多。

但 Agent 的问题不只在“会不会修改”。它还可能把读到的东西带出去。

如果一个 Agent 能读取私仓,又能创建公开评论,那么“读”和“写”已经通过上下文连起来了。公开评论就是数据出口。此时只读权限限制的是完整性风险,不是机密性风险。

可以用三个问题审查任何工程 Agent:

边界 要问的问题 高风险信号
输入 谁能触发它 外部 Issue、PR、评论可直接驱动高权限任务
权限 它能读什么 组织级泛读权限、跨仓读取无白名单
输出 它能发到哪里 公开评论、公开 PR、外部 Webhook 可回显原文

Agent 输入权限输出三道边界

三项不一定都要取消。真实工程需要自动化,也需要跨仓库。但至少要切断其中一段。公开输入触发的任务,不应拥有私仓泛读权限;需要读私仓的任务,不应直接输出到公开位置;必须公开输出时,就不应回显原始内容。

接入前先收紧边界

这件事对一线团队的启发很直接。

第一,按工作流划分身份。Issue 分类、CI 分析、文档更新不应共用一个组织级 Agent 身份。每类任务都应该有自己的仓库白名单、文件范围和工具集合。

第二,把外部文本当成数据,不要当成指令。Issue、PR 描述、评论、日志都可能由外部人员控制。它们可以被分析,但不应随意改变高权限 Agent 的任务目标。

第三,公开输出必须受限。评论和 PR 不应该只是一个通用字符串出口。涉及私有上下文时,优先输出到私有位置;必须公开时,只给结构化摘要,并在模型之外做敏感内容扫描。

第四,把 prompt injection 纳入 CI 安全测试。准备一些带诱导指令的 Issue、PR 和日志样本,验证 Agent 是否越权读取、是否回显原文、是否调用额外工具。测试目标应从模型拒绝能力转向工程边界验证:即使模型被诱导,确定性控制仍要挡住数据外流。

GitLost 最值得记住的是一条朴素的工程规律:

Agent 越像同事,越不能只按“这个账号有什么权限”来审查。必须审查完整链路:谁能指挥它,它能看到什么,它能把结果发到哪里。

在给 Agent 接上私仓之前,先画出这三条线。很多严重问题,不藏在某一项配置里,而是出现在三项配置刚好被连通的那一刻。

随机比特公众号二维码
公众号 · 随机比特
从 AI 工具热闹里拆工程真相

写边界、控制面、上下文、成本与安全。