const { NodeVM } = require("vm2"); const acorn = require("acorn"); const walk = require("acorn-walk"); const payloads = require("./payload"); const BLACKLIST = new Set(["constructor"]); function astCheck(code) { const wrapped = ` (function(){ "use strict"; ${code} }) `; const ast = acorn.parse(wrapped, { ecmaVersion: "latest" }); walk.simple(ast, { // v1 就已经有的 WithStatement() { throw new Error("with not allowed"); }, /** * ⭐⭐⭐ 关键点:只检查 解构 ⭐⭐⭐ */ ObjectPattern(node) { for (const prop of node.properties) { if (prop.type !== "Property") continue; // { constructor: x } if (!prop.computed && prop.key.type === "Identifier") { if (BLACKLIST.has(prop.key.name)) { throw new Error("Blocked destructuring key"); } } // { "constructor": x } if (!prop.computed && prop.key.type === "Literal") { if (BLACKLIST.has(prop.key.value)) { throw new Error("Blocked destructuring key"); } } // {[key]: x} // 静态分析不知道 key 是啥,那就默认危险 if (prop.computed) { throw new Error("Blocked computed destructuring"); } } }, }); } function run(code) { try { astCheck(code); const vm = new NodeVM({ sandbox: { Reflect }, }); const result = vm.run(` module.exports = (function(){ "use strict"; ${code} }).call(undefined) `); console.log("✅ EXECUTED:", result); } catch (e) { console.log("❌ BLOCKED:", e.message); } } console.log("\n=== Sandbox v2 (fix destructuring) ==="); for (const p of payloads) { console.log("\n---", p.name, "---"); run(p.code); }