云计算百科
云计算领域专业知识百科平台

一张 AVIF 图片,为什么能变成 Next.js 服务器上的原生代码执行

导语

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 穿透到原生二进制依赖。

    当框架替你“自动优化”文件时,它也替你接管了一部分文件安全责任。团队需要把这部分责任重新显式化。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 一张 AVIF 图片,为什么能变成 Next.js 服务器上的原生代码执行
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!