# 2023 年构建的 Baseten 镜像，为何在 2026 年仍持有 GitHub 管理权限？

**Summary:** Strix 发现一个 2023 年构建的 Baseten 镜像中嵌有活跃的 GitHub 管理令牌。使用 Secret Mounts 可修复构建流程，但短有效期和最小权限原则才能真正限制这类被遗忘的凭证风险。

- Canonical: https://markhuang.ai/zh/news/baseten-2023-build-github-admin-token
- Language: zh-CN
- Author: [Mark Huang](https://markhuang.ai/about)
- Published: 2026-09-15
- Section: News
- Tags: Baseten, 容器安全, GitHub 安全, 密钥管理, 供应链安全
- Source: [Strix](https://www.strix.ai/blog/baseten-harbor-github-pat-takeover)
- License: https://creativecommons.org/licenses/by-nc/4.0/

---

![一个旧的容器镜像层中包含一把发光的访问密钥，连接着多个代码库和基础设施保险库](https://cdn.markhuang.ai/news/baseten-2023-build-github-admin-token/hero.webp)

*镜像停止运行了，但埋藏在其构建历史中的权限却依然有效。*

[Strix 报告称，其自主安全代理发现](https://www.strix.ai/blog/baseten-harbor-github-pat-takeover)一个公开可下载的 Baseten 容器镜像中存在一个活跃的 GitHub 个人访问令牌。该镜像的构建时间是 2023 年 3 月 3 日。当 Strix 在 2026 年 7 月测试该令牌时，它仍然拥有对 Baseten 主产品仓库、Flux 配置仓库以及 Homebrew tap 的管理员和推送权限。

25 分钟的 AI 攻击听起来很吸引眼球。但我更在意的是这个凭证居然维持了三年多的有效权限。公开的镜像仓库暴露了这个产物，而 Docker 构建过程则记录下了这个密钥。正是这个令牌的长期有效性和宽泛权限，把两个本可挽回的失误串联成了一条能直达产品代码和部署配置的关键攻击链。

如果我在此次披露后审查一个容器流水线，我不会仅仅满足于将仓库设为私有或从当前 Dockerfile 中移除密钥。我会把每一个曾经发布过的镜像都当作一份持久记录来看待。至于每个构建凭证，我都会假定它已经泄露——除非能拿出证据：作用域足够小、有效期足够短、撤销历史也足够干净。

## 密钥并不在文件系统里

据 Strix 称，一个 Harbor 项目允许匿名拉取镜像，其中包括名为 `baseten/baseten-app` 的镜像。这种行为符合[Harbor 自身的项目模型](https://goharbor.io/docs/main/working-with-projects/create-projects/)：任何用户都可以从公共项目中拉取镜像。项目设为公共本身不算配置错误，真正关键的发现藏在镜像元数据里。

Strix 表示，他们拉取了该镜像，扫描了其各层，并检查了配置。其中发现的一对 AWS 凭证已经失效，但 GitHub 令牌仍然有效。该令牌的值出现在 `history[].created_by` 字段中，因为一条构建命令在 `RUN` 指令中展开了 `GITHUB_TOKEN` 环境变量。一个只读的 `GET /user` 请求确认该账户为 `basetenbot`。

我会把一个细节加入每份事故检查清单：仅在后续层中删除凭证文件是不够的。即使最终的文件系统看起来干净，容器元数据仍可能保留创建该层的命令。[Docker 明确警告过](https://docs.docker.com/build/building/secrets/)，构建参数和环境变量不适合用于传递密钥，因为它们可能会保留在最终镜像中。Docker 推荐改用临时的 Secret Mounts。

> **Info:**
>
> 我的审计范围会覆盖镜像配置和完整的构建历史，而不仅仅是最新层中的文件。然后我会立即撤销暴露的凭证。重新构建镜像并不能取消一个已经被复制到别处的令牌。

## 依赖拉取不需要管理员权限

这次暴露的构建使用该令牌来拉取私有的 GitHub 依赖。Strix 表示，同一个凭证被赋予了宽泛的 `repo` 权限范围，并对 `basetenlabs/baseten`、`basetenlabs/flux-cd` 和 `basetenlabs/homebrew-tap` 拥有管理员及推送权限。报告还提到它对其他私有仓库也有读写权限。Strix 称他们仅使用只读请求来确认权限，没有克隆遇到的客户仓库，也没有推送或修改任何配置。

拉取一个私有依赖只需要对该依赖的访问权限，而不应该同时拥有对产品仓库、集群期望状态和软件分发渠道的持久控制。持有该令牌的攻击者本可以有多条路径来改变 Baseten 发布或部署的内容。Strix 并未报告实际利用了这些路径，因此我会将其视为潜在后果，而非已发生的入侵。

[GitHub 当前的指南](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)建议尽可能使用细粒度令牌，因为它们可以限定到单一所有者、选定的仓库和特定权限。GitHub 还指出，长期存在的组织集成应该使用 GitHub App。细粒度令牌确实存在一些功能缺口，比如部分 Packages 和 Checks 功能，但这只是记录例外的理由，而不是给经典令牌授予机器人账户所能触及的所有仓库权限的借口。

我在[客服代理退款事件](/news/support-agent-fake-approval-4200-refund)中也做过类似区分：工具只应获得执行单一有限操作所需的权限。这里的执行者是构建过程而非语言模型，但权限隔离的原则是相同的。

## 代理声明很有趣，但并非重点

Strix 表示，他们的代理从一个域名开始，没有任何凭证或源代码。它找到了 Harbor 仓库，证实了匿名镜像拉取，排除了一个已失效的凭证，在构建历史中定位到活跃令牌，并在约 25 分钟内检查了其权限范围。这一系列操作比仅仅报告"仓库暴露了"的扫描器更有价值，因为它在不做任何改动的情况下就确认了实际影响。

我仍然会将安全发现与产品宣传分开来看。Strix 销售的就是执行这次扫描的自主测试系统，而这份披露正好展示了他们系统的时间和自主性。我没有找到 Baseten 独立发布的技术事后分析。公开文章提到 Baseten 在发布前审阅了草稿，但这并不等同于对每个细节的独立确认。

无论是否由代理在 25 分钟内完成，根本的失败都是一样的。Harbor 文档明确说明了公共项目的匿名拉取行为。Docker 文档也警告了通过构建参数传递密钥的风险。GitHub 则解释了为什么经典个人访问令牌的影响范围更广。一个使用普通工具的人类测试人员也能走通同样的路径。自动化改变的只是检查被遗忘资产的成本和频率。

## 快速响应无法抹去长期暴露

Strix 报告称，他们在 7 月 13 日晚上 11:10 通知了 Baseten。Baseten 第二天早上就将 Harbor 项目设为私有，然后在 7 月 14 日下午 4:34 确认已轮换令牌并将问题定级为严重。Strix 表示剩余问题在 7 月 17 日前已全部关闭。这确实是对严重报告的及时响应。

但这仍留下了一个令人不安的证据缺口。一个能工作三年多的令牌，光靠一个利落的收尾是不够的。我会希望审查其整个实际生命周期内的审计日志，尽可能将仓库写入、权限变更、包活动和自动化运行追溯到该凭证。当[GitHub 在 2025 年让细粒度 PAT 普遍可用时](https://github.blog/changelog/2025-03-18-fine-grained-pats-are-now-generally-available/)，还为 API 审计事件添加了 `token_id` 字段，以便管理员能按令牌筛选活动。这也是为什么我们应该优先选择那些能精确追溯到单个凭证的凭据设计。

我从 Baseten 的这次事件中学到的道理很简单：密钥必须在产物被遗忘前就过期。Secret Mounts 能防止这种持久化路径，私有仓库则能减少谁可以获取镜像。短期有效、权限最小的凭证才能把遗漏产物可能带来的风险降到最低。我希望这些控制措施能结合起来，因为 2023 年的构建不该在 2026 年还携带着生产级别的权限。
