IPBUF安全漏洞报告
English
CVE-2025-50537 CVSS 5.5 中危

CVE-2025-50537: ESLint RuleTester.run()循环引用对象序列化栈溢出漏洞

披露日期: 2026-01-26

漏洞信息

漏洞编号
CVE-2025-50537
漏洞类型
栈溢出
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
无需认证 (PR:N)
用户交互
需要交互 (UI:R)
影响产品
eslint

相关标签

栈溢出循环引用无限递归eslintRuleTester序列化JavaScriptCVE-2025-50537

漏洞概述

CVE-2025-50537是存在于eslint(一个广泛使用的JavaScript代码检查工具)9.26.0之前版本中的一个栈溢出漏洞。该漏洞位于eslint/lib/shared/serialization.js文件的序列化功能中,当处理包含循环引用的JavaScript对象时,isSerializable()函数会进入无限递归状态,最终导致栈溢出崩溃。攻击者可以通过eslint的RuleTester.run()方法触发此漏洞,该方法通常用于验证自定义规则的测试用例并检查重复项。在验证测试用例过程中,checkDuplicateTestCase()函数会被调用,该函数依赖isSerializable()进行序列化检查。当测试用例中包含循环引用对象时,序列化过程无法正确处理这种自引用数据结构,导致无限递归调用栈,最终造成应用程序栈空间耗尽。此漏洞的CVSS评分为5.5,属于中等严重程度,攻击向量为本地,需要用户交互,但无需认证即可利用。成功利用此漏洞可能导致使用eslint进行代码检查的应用程序崩溃,影响开发工作流程的连续性。

技术细节

该栈溢出漏洞的根本原因在于eslint/lib/shared/serialization.js中的isSerializable()函数缺乏对循环引用的检测和正确处理机制。在JavaScript中,对象可以包含对自身的引用(循环引用),例如:const obj = {}; obj.self = obj; 当isSerializable()函数尝试序列化这样的对象时,它会递归地遍历对象的所有属性。由于obj.self指向obj自身,函数会再次尝试序列化obj,从而陷入无限递归循环。攻击者利用RuleTester.run()方法触发漏洞的具体流程如下:首先构造一个包含循环引用的测试用例对象;然后调用RuleTester.run()方法执行该测试用例;在内部验证过程中,checkDuplicateTestCase()函数调用isSerializable()进行序列化检查;由于循环引用的存在,isSerializable()进入无限递归状态;最终调用栈深度超出JavaScript引擎的限制,导致栈溢出错误。漏洞利用的关键在于循环引用对象能够绕过isSerializable()函数的递归终止条件。由于每次递归调用都会在栈上分配新的栈帧,且函数没有深度限制检查或循环引用检测机制,因此递归调用会持续进行直到栈空间耗尽。在Node.js环境中,这通常会导致进程崩溃并抛出RangeError: Maximum call stack size exceeded错误。攻击者可以通过精心构造的测试用例或插件配置来触发此漏洞,影响任何使用eslint进行代码验证的系统。

攻击链分析

STEP 1
步骤1
攻击者准备包含循环引用的JavaScript对象,例如使用obj.self = obj创建自引用结构
STEP 2
步骤2
构造eslint RuleTester.run()的测试用例,将循环引用对象嵌入到测试配置中(如meta或options字段)
STEP 3
步骤3
调用RuleTester.run()方法执行测试验证,触发内部checkDuplicateTestCase()函数
STEP 4
步骤4
checkDuplicateTestCase()函数调用isSerializable()进行序列化检查
STEP 5
步骤5
isSerializable()函数尝试递归遍历对象属性,遇到循环引用时无法正确处理
STEP 6
步骤6
函数进入无限递归状态,调用栈深度不断增加直到超出限制
STEP 7
步骤7
栈空间耗尽导致RangeError: Maximum call stack size exceeded,进程崩溃

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
// CVE-2025-50537 PoC - ESLint Stack Overflow via Circular Reference const { RuleTester } = require('eslint'); const rule = require('./rules/example-rule'); // Assume a basic rule exists // Create circular reference object const circularObj = {}; circularObj.self = circularObj; // Create circular reference // Set up RuleTester with the vulnerable configuration const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 2024 } }); try { // Attempt to run test with circular reference - triggers stack overflow ruleTester.run('example-rule', rule, { valid: [ { code: 'var x = 1;', // Circular reference in meta or options meta: circularObj } ], invalid: [] }); } catch (error) { console.log('Test completed or error:', error.message); } // Alternative minimal PoC using direct isSerializable call if exposed // const { isSerializable } = require('eslint/lib/shared/serialization'); // const circularRef = {}; // circularRef.loop = circularRef; // isSerializable(circularRef); // Triggers infinite recursion

影响范围

eslint < 9.26.0

防御指南

临时缓解措施
在官方修复发布之前,可以采取以下临时缓解措施:1) 限制或禁用不可信来源的eslint规则测试用例执行;2) 对RuleTester.run()的输入进行严格验证,拒绝包含循环引用的对象;3) 增加Node.js的栈大小限制作为临时方案(--stack-size参数),但这只能增加有限的栈空间,无法根本解决问题;4) 使用沙箱环境隔离eslint执行,防止进程崩溃影响主应用;5) 监控和限制测试用例的复杂度,避免恶意构造的复杂测试触发漏洞。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表