导语
2026 年 8 月 25 日,Next.js 发布 15.5.24 和 16.3.3,修复两项可导致未认证远程代码执行的 Critical 漏洞。其中一项仅影响 Windows 文件系统上的服务;另一项则更具普遍的软件供应链意义:攻击者控制的 AVIF 图片进入 Next.js Image Optimization API 后,可能触发底层 libheif 的堆缓冲区越界写,最终在服务器进程中实现代码执行。
这条链跨越了开发者平时看到的多个抽象层:
next/image → Next.js Image Optimization API → sharp → libheif → C/C++ 堆内存
业务代码可能没有一行 C++,SAST 也可能没有发现危险函数,但框架提供的“自动图片优化”功能已经把复杂媒体解析器放到了网络请求路径上。
本文区分事实、推断和建议。上游公告给出了 AddressSanitizer 崩溃复现和完整测试文件生成器,但本文不会复制武器化代码;复现部分只用于隔离环境验证内存越界与补丁有效性。
一、事实速览
| Next.js 公告 | GHSA-2xp9-vwfh-vxw4 |
| 公布日期 | 2026-08-25 |
| 漏洞能力 | 未认证远程代码执行 |
| 触发组件 | Next.js Image Optimization API 处理 AVIF;底层为 sharp 使用的 libheif |
| Next.js 严重性 | Critical,CVSS 4.0 为 9.5 |
| Next.js 受影响范围 | GHSA 列出 >=10.0.0 <15.5.24 与 <16.3.3;应以对应受支持分支的修复版为准 |
| Next.js 修复版本 | 15.5.24、16.3.3 |
| 上游公告 | libheif GHSA-g89c-p67h-r497 |
| libheif 受影响版本 | <=1.23.1 |
| libheif 修复版本 | 1.23.2 |
| 上游缺陷 | scale_nearest_neighbor() 中受控堆缓冲区越界写 |
| CVE 状态 | 截至核验时间,该 AVIF/Next.js GHSA 与上游 GHSA 均未显示已分配 CVE |
| 在野利用 | 一手公告没有确认已出现针对 Next.js 的在野利用 |
事实。 Next.js 15.5.24 和 16.3.3 的发布记录均明确列出两项 Critical 修复:AVIF 图片优化 RCE,以及 CVE-2026-75604 Windows-hosted RCE。
事实。 Next.js 的临时风险控制是禁用 AVIF 优化,直到上游修复完成传播。libheif 同日发布 1.23.2;该版本是与 1.23.1 ABI/API 兼容的可直接替换安全版本,并修复多项 Critical/High 问题。
事实。 上游 libheif 维护者表示,已在多个应用中用该内存破坏实现代码执行。这证明漏洞具备 RCE 能力,但不等于所有平台、构建和 Next.js 部署都能被同一方式稳定利用。
二、背景与趋势:现代“前端框架”已经是一套服务器运行时
将 Next.js 仅理解为 React 页面框架,已经不足以评估它的攻击面。生产部署中,它可能处理:
-
服务端组件和服务端渲染;
-
路由、缓存与中间件;
-
文件系统和构建产物;
-
Server Actions 与 API 请求;
-
远程图片获取、解码、缩放、转码和缓存。
图片优化尤其危险,因为它同时满足三项高风险条件:输入格式复杂、经常处理外部内容、底层依赖原生内存不安全代码。HEIF/AVIF 又建立在 ISO Base Media File Format 的对象、引用和派生关系之上,不只是简单的像素矩阵。
推断。 本次事件反映出三条值得 DevSecOps 团队关注的趋势:
框架功能正在扩大隐式 SBOM。 应用直接声明的可能只有 next,运行时风险却来自 sharp、预编译原生二进制和 libheif。
便利 API 正在成为解析边界。 图片、PDF、视频、压缩包和模型文件只要在服务器端“自动处理”,就应按不可信反序列化入口建模。
仅做 JavaScript SCA 不够。 锁文件能告诉你 npm 包版本,却未必完整反映预编译二进制中链接了哪个 C/C++ 库及其补丁状态。
这些是基于组件架构的趋势判断,不是官方对受影响 Next.js 网站数量的统计。
三、调用链:攻击输入怎样到达原生解码器
Next.js 的 <Image> 组件和 Image Optimization API 可以按请求尺寸处理本地或配置允许的远程图片。相关请求通常由 /_next/image 路径承载,再交给图片处理依赖完成解码和输出。
对于本次漏洞,可以把已确认的关键链条抽象为:
攻击者可控的 AVIF/HEIF 内容
│
▼
Next.js Image Optimization API
│
▼
sharp 的图片处理路径
│
▼
libheif: heif_decode_image()
│
▼
派生图片与 Alpha 平面组合、缩放
│
▼
scale_nearest_neighbor() 堆越界写
事实。 Next.js GHSA 的表述是:当 AVIF 文件被优化时,底层 libheif 漏洞可导致 RCE。攻击不需要事先权限或用户交互,但 CVSS 4.0 将 Attack Requirements 标为 Present。
推断。 对具体应用而言,必要的可达条件通常包括:攻击者能让恶意 AVIF 成为优化器输入,例如应用优化了用户上传内容,或允许从攻击者可控制/可替换的远程来源取图。若图片完全由可信构建产物提供,且外部输入无法到达优化路径,实际可利用性会下降;但这不能替代升级,因为配置和内容来源会变化。
四、技术原理:四个“单看没那么危险”的行为怎样组成堆溢出
上游 GHSA 对根因公开得非常具体。它不是一个简单的“宽高相乘溢出”,而是对象引用、重复通道、位深查询和缩放写入共同形成的状态错乱。
1. 嵌套 iden 与 auxl 产生重复 Alpha 平面
HEIF/AVIF 容器中的项目可以引用其他项目:
-
iden 表示身份派生,复用被引用图像;
-
auxl 可把另一个项目作为辅助图像,例如 Alpha 透明度平面。
构造文件让一个 iden 项目先继承被引用图像已有的 8-bit Alpha,再附加自身的 10-bit Alpha。结果是同一解码图像内部同时存在两个标记为 Alpha 的存储项。
2. 写入重复通道时没有拒绝
transfer_channel_from_image_as() 会改变源平面的通道类型并追加到 m_storage,但旧实现没有拒绝已经存在的目标通道。上游公告甚至指出源码中保留了“检查目标通道是否已经存在”的 TODO。
这使 [Alpha(8-bit), Alpha(10-bit)] 这样的内部状态成为可能。
3. 查询只返回第一个 Alpha
find_storage_for_channel() 遇到重复通道时只返回第一个匹配项。于是获取 Alpha 位深、内存地址、宽高等操作描述的是第一个 8-bit Alpha,而后续迭代仍能遍历到第二个 10-bit Alpha。
此时对象已经出现典型的不变量破坏:
“Alpha 通道”查询结果:8 bit
实际待处理的另一个 Alpha:10 bit
4. 按 8 bit 分配,按 16 bit 写入
缩放函数先依据第一个 Alpha 的信息创建输出平面,每个像素分配 1 字节。随后遍历所有存储项,处理到 10-bit Alpha 时进入 HDR 分支,将同一目标内存作为 uint16_t* 使用,每个像素写入 2 字节。
上游示例的输出几何为 128×128:
目标分配:128 × 128 × 1 byte = 16,384 bytes
后续写入:128 × 128 × 2 bytes = 32,768 bytes
结果是约 16,384 字节写出分配区域。容器几何控制溢出范围,HEVC 10-bit 样本控制写入的 16 位值,因此上游将其视为攻击者可控的堆越界写。
5. 为什么会进入缩放
旧实现中,iden 的尺寸检查会无条件成功。攻击文件可以让派生项目声明的尺寸与实际解码尺寸不同;当它作为另一个项目的 Alpha 辅助图像时,尺寸不匹配触发 scale_nearest_neighbor(),最终到达越界写位置。
这条漏洞链的关键教训是:每个局部函数都可能“正常工作”,但它们共同依赖的全局不变量——通道唯一、平面位深一致、几何一致——已经失效。
五、真实可复现案例:在 ASan 下验证越界,不验证武器化 RCE
上游 GHSA 提供了完整测试容器生成器和 AddressSanitizer 复现步骤。安全团队可以在无生产数据、无云凭据、无外网权限的临时容器或虚拟机中复现。
建议流程:
获取 libheif 1.23.1 源码并固定提交/标签;
使用 Clang,以 -fsanitize=address -fno-omit-frame-pointer -g 构建 heif-dec;
从上游 GHSA 获取其测试文件生成器,审核后在隔离目录生成 poc.heic;
用 ASan 构建的 heif-dec 解码测试文件;
预期看到 scale_nearest_neighbor() 中 WRITE of size 2 的 heap-buffer-overflow 报告;
将依赖升级到 libheif 1.23.2,重新构建并运行同一回归用例,确认不再出现越界;
销毁临时环境,不将测试文件上传到公共网站或第三方扫描服务。
事实。 上游公告给出的调用栈包含 HeifPixelImage::scale_nearest_neighbor()、ImageItem::decode_image()、HeifContext::decode_image() 和 heif_decode_image(),分配发生在 Alpha 平面创建路径。
边界说明。 ASan 崩溃证明内存安全缺陷可触发,并不等同于在你的系统上完成 RCE。利用稳定性还会受到分配器、编译选项、ASLR、容器权限、进程模型和操作系统影响。本文不建议也不提供将越界写转化为代码执行的步骤。
六、风险影响:首先判断“是否可达”,然后按 RCE 处置
已确认影响
Next.js 将该问题评为 Critical,CVSS 4.0 为 9.5;网络攻击者无需权限和用户交互,成功利用可对当前系统及后续系统的机密性、完整性和可用性造成高影响。
高优先级部署
-
自托管 Next.js,使用内置 Image Optimization API;
-
允许优化用户上传的 AVIF/HEIF 文件;
-
remotePatterns 或其他业务逻辑允许从外部内容源获取图片,而该来源可被用户控制;
-
图片优化进程持有云凭据、数据库访问、内部网络权限或可写应用文件;
-
仍运行 Next.js 10—14 或未修补的 15/16 分支;
-
基础镜像中存在独立使用的旧版 libheif,即使 Next.js 已升级。
需要单独核验的情况
使用自定义图片 CDN、托管平台重写 /_next/image、全局 unoptimized 或完全静态导出的部署,可能不经过受影响的 Next.js 原生优化路径。Netlify 的官方说明就是一个真实例子:其边缘层把该路径改写到 Image CDN,因此不运行受影响代码;但平台仍建议升级。
建议。 不要根据“我们没主动配置 AVIF 输出”直接判定不受影响。应检查攻击者能否提供 AVIF 输入、运行时实际请求路径和部署平台实现。
七、开发与安全团队可执行的防护建议
P0:立即升级和重新部署
升级到 Next.js 15.5.24 或 16.3.3 及以上版本,重新生成锁文件、重新构建并部署;不要只在仓库里修改 package.json。
对已经停止维护的 Next.js 10—14 应用制定升级路径。官方本次补丁版本位于 15.5 与 16.3 维护线,不能假设旧主版本会自动获得回移。
若不能立即升级,停止让不可信 AVIF 进入服务器端优化流程;使用不会调用受影响代码路径的可信 CDN/隔离转换服务。Next.js 公告所采用的临时控制是禁用 AVIF 优化。
如果应用在 Windows 上托管,同时评估同批次的 CVE-2026-75604;它没有已知临时绕过方案,官方要求立即升级。
P0:验证实际运行产物
-
执行 npm ls next sharp、pnpm why 或对应包管理器命令,记录解析到的版本;
-
检查容器镜像内实际安装的 Next.js、sharp 和原生 .node 文件,而不是只看工作站锁文件;
-
确认所有副本、灰度实例、Serverless 函数和灾备环境均已替换;
-
通过构建证明或制品摘要把“源码已修”关联到“运行制品已修”;
-
扫描系统包和其他应用是否直接携带 libheif <=1.23.1。
P1:调查暴露窗口
截至核验时间,官方未确认针对 Next.js 的在野利用,但对具备可达条件的公网应用仍建议:
-
查询 /_next/image 请求,重点关注 AVIF/HEIF 来源、异常来源域、非常规尺寸参数和大量失败请求;
-
保留反向代理、CDN、应用、容器与主机日志;
-
检查图片优化进程异常退出、原生崩溃、OOM、容器重启和 core dump;
-
审核进程能够访问的环境变量、云角色、挂载卷和内部服务;
-
若发现可疑内存破坏或异常执行迹象,按入侵事件轮换密钥并重建实例,而不是只重启服务。
这些是事件响应建议,不代表已确认存在针对你的攻击。
P1:让图片处理成为独立安全域
将图片解码放入无云凭据、只读根文件系统、低权限用户的独立进程或容器;
禁止不必要的出站网络,限制可读取路径和可写临时目录;
设置输入字节数、像素数、宽高、处理时间和内存上限;
对允许的源域使用精确 remotePatterns,不要配置宽泛通配符;
对上传内容先做魔数和结构检测,但不要把 MIME/扩展名校验视为内存安全保证;
将转换结果写入对象存储,由业务进程读取成品,避免业务 Web 进程直接解析复杂原始文件。
P2:改进 DevSecOps 与供应链治理
-
在 SBOM 中记录 npm 包、原生扩展及其嵌入/动态链接库;
-
对预编译二进制保留平台、架构、哈希和构建来源;
-
将上游 GHSA 与框架下游 GHSA 建立传播关系,而不是把它们视为两个无关漏洞;
-
对媒体解析器启用持续 fuzzing、ASan/UBSan 和官方安全回归语料;
-
为功能开关维护“能力清单”:开启图片优化等同于新增一个文件解析服务;
-
在威胁模型中标注不可信文件从 URL、上传、CMS、对象存储到解码器的完整数据流。
八、代码评审应该学到什么
本次根因可以转化为一组通用审计问题:
-
容器或对象图是否允许同一逻辑通道出现多次?
-
查询函数返回“第一个匹配项”时,调用方是否错误假设唯一性?
-
分配依据与写入依据是否来自同一个经过验证的元数据对象?
-
位深、尺寸、步长和分量数在跨函数传递时是否保持一致?
-
派生对象是否绕过了普通对象必须执行的尺寸与资源限制?
-
断言是否被当作生产环境输入校验?
-
每个消费点是否重新验证平面几何,而不是相信早期解析结果?
libheif 1.23.2 的加固措施也很有代表性:在消费平面的位置验证尺寸、让 iden 执行尺寸检查、把部分断言替换为运行时错误,并限制解压输出与派生引用的资源放大。
总结
这次 Next.js AVIF 漏洞最值得记住的,不是“图片也能 RCE”这句标题,而是抽象层如何隐藏真实攻击面:开发者调用的是 <Image>,服务器执行的是复杂的 C/C++ 容器解析、HEVC 解码、通道组合和缩放逻辑。
事实结论: Next.js 于 2026-08-25 发布 15.5.24 和 16.3.3;旧版本在优化恶意 AVIF 时可能因底层 libheif 堆越界写而发生未认证 RCE。上游 libheif 1.23.2 已修复该缺陷。
技术推断: 实际可达性取决于恶意 AVIF 能否进入优化 API,但配置或托管路径降低可达性不等于可以长期不升级。
行动建议: 立即升级并验证运行制品;在暴露窗口内检索图片优化异常;长期把媒体解析器从业务进程隔离,并让 SBOM 穿透到原生二进制依赖。
当框架替你“自动优化”文件时,它也替你接管了一部分文件安全责任。团队需要把这部分责任重新显式化。
网硕互联帮助中心



评论前必须登录!
注册