事件报告:GitHub 个人访问令牌泄露
2024 年 6 月 28 日,security@pypi.org 和我 (Ee Durbin) 收到通知,我的 GitHub 用户帐户 ewdurbin
的 GitHub 个人访问令牌被泄露。该令牌已立即被撤销,并对我的 GitHub 帐户和活动进行了审查。未发现任何恶意活动的迹象。
事件时间线
- 2023-MM-DD1:为
ewdurbin
创建了一个 GitHub 个人访问令牌。该令牌对我的用户的所有组织和存储库2(包括pypi
、python
、psf
和pypa
)具有推送、拉取和管理员访问权限。 - 2023-03-033:
cabotage/cabotage-app:v3.0.0b35
推送到 hub.docker.com,其中包含ewdurbin
的 GitHub 个人访问令牌,位于一个.pyc
文件中。 - 2023-07-203:
cabotage/cabotage-app:v3.0.0b110
推送到 hub.docker.com,其中包含ewdurbin
的 GitHub 个人访问令牌,位于一个.pyc
文件中。 - 2024-06-21:
cabotage/cabotage-app:v3.0.0b35
和cabotage/cabotage-app:v3.0.0b110
从 hub.docker.com 中删除,原因与本报告无关4。 - 2024-06-28 7:09 AM 东部时间:JFrog 的 Brian Moussalli 向 security@pypi.org 和 Ee 的个人电子邮件地址报告了他们发现
ewdurbin
的 GitHub 个人访问令牌。 - 2024-06-28 7:26 AM 东部时间:
ewdurbin
的 GitHub 个人访问令牌被销毁。
事件是如何发生的
在本地开发 cabotage-app
5 时,我正在处理代码库的构建部分,一直遇到 GitHub API 速率限制。这些速率限制适用于匿名访问。虽然在生产中,系统被配置为 GitHub 应用程序,但我修改了我的本地文件,以便在懒惰的情况下将自己的访问令牌包含在内,而不是配置一个 localhost
GitHub 应用程序。这些更改从未打算远程推送。
diff --git a/cabotage/celery/tasks/build.py b/cabotage/celery/tasks/build.py
index 0f58158..3b88b5d 100644
--- a/cabotage/celery/tasks/build.py
+++ b/cabotage/celery/tasks/build.py
@@ -395,7 +395,10 @@ def build_release_buildkit(release):
def _fetch_github_file(
- github_repository="owner/repo", ref="main", access_token=None, filename="Dockerfile"
+ github_repository="owner/repo",
+ ref="main",
+ access_token="0d6a9bb5af126f73350a2afc058492765446aaad",
+ filename="Dockerfile",
):
g = Github(access_token)
try:
@@ -407,7 +410,13 @@ def _fetch_github_file(
return None
虽然我很清楚 .py
文件中泄漏令牌的风险,但我没有考虑到包含编译字节码的 .pyc
文件。
当时,使用以下脚本执行暂存部署,该脚本尝试但未能删除临时应用的更改,包括硬编码的密钥。
#!/bin/bash
generation=$(cat generation)
git stash
docker buildx build --platform linux/amd64,linux/arm64 -t cabotage/cabotage-app:v3.0.0b${generation} --push .
kubectl -n cabotage set image deployment/cabotage-app cabotage-app=cabotage/cabotage-app:v3.0.0b${generation} cabotage-app-worker=cabotage/cabotage-app:v3.0.0b${generation} cabotage-app-beat=cabotage/cabotage-app:v3.0.0b${generation}
git stash pop
echo $((generation + 1)) > generation
由于应用程序一直在 Docker 中的共享卷上本地运行,因此仍然存在包含本地和未提交更改的 .pyc
文件。当时,一个最小的 .dockerignore
文件 并没有从构建中排除 __pycache__
或 *.pyc
文件,导致密钥泄露。
响应
除了撤销令牌并审查我可获得的几乎所有 GitHub 审计日志和帐户活动,以查找可能对令牌的恶意使用之外,还做了一些更改来降低此类泄露的未来风险。
Cabotage 现在完全自托管,这意味着 cabotage-app 的构建不再使用公共注册表6,部署构建从源代码的干净签出开始。这缓解了本地编辑进入开发环境之外的镜像构建的场景,也消除了发布到公共注册表的必要性。
我已经撤销了与我的帐户相关的唯一一个 GitHub 访问令牌,并且在未来将避免创建令牌,除非绝对必要,并且会确保令牌有内置的过期时间。除了这个奇怪的使用案例,我不记得我的用户曾经使用过长时间的令牌,并且拥有一个令牌以便我在懒惰时使用,似乎风险大于收益。
收获
这是一个很好的提醒,要为 API 令牌设置激进的过期日期(如果需要的话),将 .pyc
文件视为源代码,并仅从干净的源代码中执行自动化系统的构建7。
感谢
首先,感谢 JFrog 的团队发现并报告了这次泄漏。您可以在他们的博客上阅读有关此发现的博客文章 他们的博客。
我们感谢整个安全研究人员社区对 Docker Hub 和 PyPI 本身等公共存储库进行的扫描。PyPI 依赖于这个社区的努力来检测 上传到 PyPI 的恶意软件,并与 GitHub集成,以自动处理提交中泄露的 PyPI 凭据,以及 公共问题中的凭据。所有各方之间的合作有助于提高开源的安全性,我们谁也无法单独做到这一点。
Ee Durbin 是 Python 软件基金会的基础设施总监。自 2013 年以来,他一直在为保持 PyPI 在线、可用和安全而贡献力量。
-
确切日期未知,因为 GitHub 帐户安全日志 无法获取超过 90 天的日志。 ↩
-
此令牌的具体权限未知,因为它们没有保留在 GitHub 帐户安全日志中,并且在令牌被销毁之前没有被记录。我们已经询问 JFrog 他们的发现是否包含令牌级别权限,如果他们提供,我们将更新此帖子。
编辑:JFrog 于 2024 年 7 月 9 日从他们的发现中提供了这些日期。 ↩
-
发布时间未知,因为 hub.docker.com 不会保留任何已删除镜像的历史记录。我们已经询问 JFrog 他们的发现是否包含发布时间,如果他们提供,我们将更新此帖子。
-
cabotage-app
已经将构建迁移到自动化系统。hub.docker.com 上的镜像不再需要,并已主动删除。 ↩ -
cabotage 是部署 warehouse 代码库 以及构成 PyPI 的相关服务的代码库。您可以在我们博客中发布的关于 代码库的安全审计 的博客文章中了解有关 cabotage 的更多信息。 ↩
-
更重要的是,用于 cabotage 构建的内部私有注册表使用 细粒度的 Docker 身份验证,只允许指定的 Kubernetes 服务帐户访问镜像。 ↩