不可信的上游:该提供者获取了其响应所指示的 URL。
Drupal OpenAI Provider(ai_provider_openai)· SSRF(CWE-918)· CVE-2026-13233 · SA-CONTRIB-2026-053
状态: 协调披露 已完成(2026-07-10)。 已私下报告给 Drupal 安全团队,已修复,并以 CVE-2026-13233 / 公告 SA-CONTRIB-2026-053 发布(评级为 中度严重)。作者被列为 发现者与修复开发者。
针对 AI“连接点”上典型的授权 / 输入验证缺陷的研究:AI 图像生成提供者使用没有协议白名单的通用函数获取了上游 API 响应中包含的 URL。在配置的上游不是受信任默认值(自带端点 / 代理 / 自托管网关 / 受损中继)的部署中,响应可能将服务器指向 file:// 或内部地址。
到达风险点的不可信输入是上游响应 URL——而不是用户的提示。
file:// 本地文件读取;作者的内部分析还将其映射到 CWE-73 / CWE-441。3.1 / 有条件 5.3(中危);先前 6.5 / 7.4 的评估已撤回,中段评级也印证了这一点。ai_provider_openai)< 1.1.1 及 1.2.0–1.2.1(审计版本 1.2.1),基于 Drupal core 11.2所有验证均在自有、网络隔离的沙箱中针对模拟上游进行。从未调用真实 OpenAI API。泄漏 oracle 仅为合成数据。
已确认(动态论证):
settings.php 的读取通过 sha256 字节匹配(35,182 字节)得到确认——内容从未被打印;因此数据库凭证属于影响范围。未验证(明确不主张):
不受影响: 默认的 api.openai.com(通过 TLS)。host 设置由管理员 / 配置同步 / 部署控制——运行时的非管理员攻击者无法更改它。
响应 URL 被传递给了尊重每个已注册 PHP 流包装器(file、php、http、data、phar 等)的通用抓取函数。response_format 默认为 url,因此易受攻击的分支就是默认路径。file:// 是 PHP 的默认文件系统包装器,且不受 allow_url_fopen 的限制(早先“需要 allow_url_fopen”的说法是错误的,现已撤回)。
修复底层原语,而不仅是修复调用点:
http / https;禁用重定向(30x 可跳转到 file://)。file://…、http://169.254.169.254/… 以及 302→file:// 重定向都必须被拒绝。完整方向:docs/fix-direction.md。
.
├── README.md # this file (English, canonical)
├── README_ja.md # Japanese mirror
├── SECURITY.md # reporting policy + responsible-disclosure disclaimer
├── .gitignore # blocks secrets / primary evidence from being committed
├── docs/
│ └── fix-direction.md # root-cause fix + variant hunt + minimal-diff sketch (EN)
├── reproducer/ # SAFE reproducer only (sandbox, mock upstream, benign oracle)
│ ├── README.md # how to stand up the network-isolated sandbox
│ ├── verdict.md # what "success" means: raw-byte match + 200-vs-403 + exit codes
│ ├── mock-openai-server.py # benign mock; default happy-path PNG, ssrf_demo → file:///etc/hostname only
│ └── docker-compose.yml # TEMPLATE: isolated Drupal sandbox + mock (you add the vulnerable target)
├── detections/
│ ├── README.md
│ ├── sigma/web-egress-to-internal-after-imagegen.yml
│ ├── sigma/php-sensitive-file-open.yml
│ ├── sentinel/imagegen-egress-correlation.kql
│ └── splunk/imagegen-content-type-mismatch.spl
└── timeline.md # disclosure timeline (single source of truth)
文档目前是日文(
.ja.md);英文权威翻译是待办事项。本仓库中不包含: 武装载荷以及任何开箱即用的文件读取 PoC。公开的reproducer/使用单个良性 oracle(/etc/hostname)针对模拟上游演示缺陷机制——没有任意路径读取,没有settings.php抓取,没有 IMDS。它不是针对在线站点的武器。请更新到 1.1.1 / 1.2.2。
目标: 让研究人员能够确认缺陷类别,而无需提供针对真实目标的利用或暴露机密。一切均在离线环境下运行。
docker compose 在隔离网络上运行应用和模拟上游(语言原语检查使用 --network none)。不挂载任何凭证。模拟上游从不与真实 API 通信。host”。它通过带外方式(而非提示词)被武装,以返回一个合成目标 URL——这体现了修正后的攻击者模型(上游选择 URL,用户仅触发)。file:///etc/hostname 以及仅在应用容器内写入的每次运行唯一标记 → 证明应用读取了由上游选择的路径(标记在模拟上游中不存在)。settings.php 通过 sha256 字节匹配验证,内容从未被输出 → 在不泄露凭证的前提下证明“数据库凭证在影响范围内”。0 可利用 / 1 前置条件 / 2 未复现 / 3 清理失败 / 99 错误)。参见 reproducer/verdict.md。参见 timeline.md。摘要:
实践者检测位于 detections/;原理说明见 docs/detection-engineering.md。简而言之:
169.254.169.254 / 环回 / RFC1918 地址的异常出口流量(代理 / EDR)进行关联。不要仅凭出口流量告警。file:// 读取不会触网——通过主机审计(auditd/EDR)检测Web 进程打开敏感文件,并建立基线,使只有图像生成请求中偏离模式的读取才会触发。image/* 但魔数不是图像的字节。{request_id, actor, target_url, scheme, resolved_ip, content_type}。仅靠标准日志无法捕获此类问题。file:// 是默认文件系统包装器;不受 allow_url_fopen 限制)reproducer/ 是仅沙箱专用的,使用合成 oracle。它不是针对真实目标的利用工具,也不包含任何机密。切勿对你不拥有且未经授权测试的系统运行它。所有研究均由作者在自有的、网络隔离的沙箱中针对模拟上游进行——从未联系真实厂商 API,也从未测试任何第三方系统。 该发现首先私下报告给 Drupal 安全团队,并且仅在修复和公告(SA-CONTRIB-2026-053、CVE-2026-13233)同步发布后才公开;厂商评级为 中度严重。作者的 CVSS 数值是临时性自我评估,并非官方评分,且有意保持保守(无 CVSS 严重 / 高危)——这与厂商的中段评级一致。本材料仅用于防御和教育目的。参见 SECURITY.md。
| Date | Event |
|---|
| 2026-06-10 | 静态审查定位到风险点;固定路径 file:// 读取经动态验证 |
| 2026-06-11 | 任意路径读取 + settings.php sha256 匹配 + 内部 HTTP SSRF 均确认 |
| 2026-06-11 | 生产消费方可达性(自动化器内部路径;FWA 合法 HTTP 外渗) |
| 2026-06-11 | 独立同行评审纠正过度主张(攻击者模型、CVSS、allow_url_fopen);提交被置于 HOLD |
| 2026-06/07 | HOLD 项已清除;私下报告给 Drupal 安全团队;基类孪生问题标记给 drupal/ai |
| 2026-07-10 | 修复版本 1.1.1 / 1.2.2 发布;公告 SA-CONTRIB-2026-053 和 CVE-2026-13233 发布;作者被列为 发现者与修复开发者 |