图片处理代理 imgproxy 的 ICO 加载路径被披露 3 个漏洞,全部无需认证即可触发。最高一条 CVE-2026-123614 的 CVSS 3.1 评分为 9.8,成因是 data_size 字段的整数回绕导致堆缓冲区溢出;另有两条 8.7 分的越界读写与无上限内存分配。攻击者不需要登录、不需要合法签名,只要能让服务端处理一张构造过的 ICO 图片,就能让 worker 崩溃,理论上还能走到代码执行。
事件概述
三个漏洞都落在 imgproxy 依赖的 libvips 的 ICO 解码器 vips/icoload.c 中。GitHub 安全公告于 2026 年 10 月 30 日发布,CVE 记录在 11 月 8 日完成建档,分配方为 VulnCheck。修复版本分两批:CVE-2026-123614 与 CVE-2026-123616 在 4.0.16 修复,CVE-2026-123615 需要 4.0.17。项目当前最新发布为 4.0.22(2026 年 11 月 5 日)。
imgproxy 在国内多用于电商、图床、壁纸站与 CDN 回源链路,典型部署是直接暴露在公网、接受用户上传或第三方 URL 拉取,然后按参数实时缩放裁剪。这类服务天然是「把不可信图片喂给解码器」的架构,也正是本轮漏洞的触发前提。
三个漏洞的技术细节
- CVE-2026-123614(9.3 / 3.1 向量 9.8,CWE-190):整数溢出。ICO 目录项里声明的
data_size在分配时发生回绕,实际分配的缓冲区小于后续写入的字节数,堆内存被覆盖,可导致崩溃或代码执行。影响 4.0.0 至 4.0.15。 - CVE-2026-123615(8.7 / 7.5):BMP 头重建时的越界堆读写。当 ICO 条目声明一个极小的数据长度时,
vips_foreign_load_ico_header会读取并写回未经校验的头部字段,越过已分配的缓冲区,破坏相邻堆块的元数据,最终触发 glibc abort 使 worker 崩溃。影响 3.3.0 起至 4.0.16。 - CVE-2026-123616(8.7 / 7.5):无上限内存分配。
data_size未做校验,一个仅 23 字节的 ICO 文件声明约 4GB 的数据长度,服务端就按这个体积去分配内存,直接耗尽内存并把 worker 拖死。影响 3.3.0 至 4.0.15。
三条漏洞的攻击成本差异很大:123616 只需要改四个字节,是最容易复现的 DoS;123614 需要精确控制回绕后的长度,技术门槛更高,但收益也从「打崩」升级到「可能执行代码」。三者共用同一条入口——把 ICO 交给解码器——因此单一的输入过滤即可同时缓解。
影响评估
imgproxy 的常规用法是 /unsafe/ 前缀免签名缩放,或使用 HMAC 签名 URL。前者对任何能访问服务的人开放,后者只在业务方真正签发 URL 时才安全。如果部署时为了图省事开启了 IMGPROXY_ALLOWED_SOURCES 之外的宽松配置,攻击者可以自行拼出处理请求,无需任何凭据。
需要指出,imgproxy 通常是横向扩展的多个 worker 共享同一入口,单次崩溃只损失一个 worker,但攻击者可以持续重放。真正危险的不是可用性,而是 123614 那条堆溢出——在容器里跑、没有 seccomp 与只读根文件系统的情况下,堆破坏有机会转化为容器内的代码执行。EPSS 目前给出的分数很低(123614 约 0.66%,第 52 百分位),同样是刚公开导致的样本不足,不宜作为缓期理由。
为什么 ICO 成了高危入口
ICO 在图片处理链路里属于典型的「冷门格式、老代码路径」。多数团队在上线时只测过 JPEG、PNG、WebP,ICO 往往只是解码库顺手支持的一项,既没有专门测试用例,也很少有人想到要去限制它。而 ICO 的文件结构又特别适合做手脚:目录项里同时有偏移量与长度字段,长度字段一旦被乘上通道数或位深去做分配计算,就容易出现整数回绕;长度与真实数据长度不一致时,解码器还会按声明值去重建 BMP 头,越界读写随之而来。
这三条漏洞其实是同一种结构缺陷的三种表现:入口处相信了文件自己声明的长度。修复方式是在分配前做溢出检查与上限校验;而防守方的对应做法,就是在入口处不相信任何未经校验的声明长度——升级、限流、按魔数拦截,三步都指向同一件事。
修复建议
- 升级到 4.0.22 或更高版本,一次性覆盖三条漏洞;仅升到 4.0.16 会漏掉 CVE-2026-123615。
- 业务不处理 ICO 的,在网关或反向代理层直接按文件魔数拦截(ICO 头为
00 00 01 00),把攻击面从解码器前面切掉。这是升级之外性价比最高的一步。 - 关闭
/unsafe/免签名模式,改为 HMAC 签名 URL,确保只有业务方签发的请求才能进入处理管线。 - 为 imgproxy 容器设置内存上限与只读根文件系统,启用 seccomp 默认配置,把堆溢出的后续影响限制在单个 worker 内。
- 在 Worker 前加一层重试与熔断,对同一来源高频触发的解码失败做限速,避免持续重放把整个池打空。
- 排查历史记录:图片处理日志中出现解码失败、进程重启、OOM kill 的时间点,对照请求里带 ICO 或异常
Content-Type的条目。