runframe 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/async.d.ts +38 -0
- package/dist/async.d.ts.map +1 -0
- package/dist/async.js +98 -0
- package/dist/async.js.map +1 -0
- package/dist/benchmark.d.ts +9 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +216 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/capabilities.d.ts +26 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +110 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/deterministic.d.ts +81 -0
- package/dist/deterministic.d.ts.map +1 -0
- package/dist/deterministic.js +135 -0
- package/dist/deterministic.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +24 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +42 -0
- package/dist/limits.js.map +1 -0
- package/dist/memory-optimization.d.ts +43 -0
- package/dist/memory-optimization.d.ts.map +1 -0
- package/dist/memory-optimization.js +103 -0
- package/dist/memory-optimization.js.map +1 -0
- package/dist/optimization-examples.d.ts +33 -0
- package/dist/optimization-examples.d.ts.map +1 -0
- package/dist/optimization-examples.js +255 -0
- package/dist/optimization-examples.js.map +1 -0
- package/dist/optimized-index.d.ts +12 -0
- package/dist/optimized-index.d.ts.map +1 -0
- package/dist/optimized-index.js +9 -0
- package/dist/optimized-index.js.map +1 -0
- package/dist/optimized-sandbox.d.ts +77 -0
- package/dist/optimized-sandbox.d.ts.map +1 -0
- package/dist/optimized-sandbox.js +153 -0
- package/dist/optimized-sandbox.js.map +1 -0
- package/dist/sandbox.d.ts +25 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +55 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/script-cache.d.ts +48 -0
- package/dist/script-cache.d.ts.map +1 -0
- package/dist/script-cache.js +97 -0
- package/dist/script-cache.js.map +1 -0
- package/dist/stats.d.ts +41 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +70 -0
- package/dist/stats.js.map +1 -0
- package/dist/test-corpus.d.ts +15 -0
- package/dist/test-corpus.d.ts.map +1 -0
- package/dist/test-corpus.js +225 -0
- package/dist/test-corpus.js.map +1 -0
- package/dist/vm-runtime.d.ts +21 -0
- package/dist/vm-runtime.d.ts.map +1 -0
- package/dist/vm-runtime.js +276 -0
- package/dist/vm-runtime.js.map +1 -0
- package/dist/worker-pool.d.ts +62 -0
- package/dist/worker-pool.d.ts.map +1 -0
- package/dist/worker-pool.js +144 -0
- package/dist/worker-pool.js.map +1 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +39 -0
- package/dist/worker.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape test corpus: Known sandboxing attacks that MUST fail
|
|
3
|
+
* Used to verify the sandbox actually blocks dangerous operations
|
|
4
|
+
*/
|
|
5
|
+
export const ESCAPE_TESTS = [
|
|
6
|
+
{
|
|
7
|
+
name: "Prototype poisoning: Array.prototype.push",
|
|
8
|
+
code: `
|
|
9
|
+
Array.prototype.push = function() { throw new Error("ESCAPED!"); };
|
|
10
|
+
const arr = [];
|
|
11
|
+
arr.push(1);
|
|
12
|
+
`,
|
|
13
|
+
shouldBlock: true
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "Prototype poisoning: Object.prototype.toString",
|
|
17
|
+
code: `
|
|
18
|
+
Object.prototype.toString = () => "ESCAPED";
|
|
19
|
+
({}).toString();
|
|
20
|
+
`,
|
|
21
|
+
shouldBlock: true
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "Function constructor escape",
|
|
25
|
+
code: `
|
|
26
|
+
const fn = Function("return process.env");
|
|
27
|
+
fn();
|
|
28
|
+
`,
|
|
29
|
+
shouldBlock: true
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "eval() forbidden",
|
|
33
|
+
code: `
|
|
34
|
+
eval("process.exit(1)");
|
|
35
|
+
`,
|
|
36
|
+
shouldBlock: true
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "require() forbidden",
|
|
40
|
+
code: `
|
|
41
|
+
const fs = require("fs");
|
|
42
|
+
fs.readFileSync("/etc/passwd");
|
|
43
|
+
`,
|
|
44
|
+
shouldBlock: true
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "process global forbidden",
|
|
48
|
+
code: `
|
|
49
|
+
process.exit(1);
|
|
50
|
+
`,
|
|
51
|
+
shouldBlock: true
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "Worker threads forbidden",
|
|
55
|
+
code: `
|
|
56
|
+
const { Worker } = require("worker_threads");
|
|
57
|
+
new Worker("x.js");
|
|
58
|
+
`,
|
|
59
|
+
shouldBlock: true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "Buffer forbidden",
|
|
63
|
+
code: `
|
|
64
|
+
const buf = Buffer.alloc(1024);
|
|
65
|
+
buf.toString();
|
|
66
|
+
`,
|
|
67
|
+
shouldBlock: true
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "Dynamic import forbidden",
|
|
71
|
+
code: `
|
|
72
|
+
import("fs").then(m => m.readFileSync("/"));
|
|
73
|
+
`,
|
|
74
|
+
shouldBlock: true
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "Constructor property escape",
|
|
78
|
+
code: `
|
|
79
|
+
const arr = [];
|
|
80
|
+
const Ctor = arr.constructor.constructor;
|
|
81
|
+
const fn = new Ctor("return process");
|
|
82
|
+
fn();
|
|
83
|
+
`,
|
|
84
|
+
shouldBlock: true
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "Symbol.iterator manipulation",
|
|
88
|
+
code: `
|
|
89
|
+
Array.prototype[Symbol.iterator] = function() {
|
|
90
|
+
throw new Error("ESCAPED");
|
|
91
|
+
};
|
|
92
|
+
const arr = [1, 2, 3];
|
|
93
|
+
for (const x of arr) {}
|
|
94
|
+
`,
|
|
95
|
+
shouldBlock: true
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "__proto__ poisoning",
|
|
99
|
+
code: `
|
|
100
|
+
const obj = {};
|
|
101
|
+
obj.__proto__.ESCAPED = true;
|
|
102
|
+
({}).ESCAPED;
|
|
103
|
+
`,
|
|
104
|
+
shouldBlock: true
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "Constructor.constructor escape via array",
|
|
108
|
+
code: `
|
|
109
|
+
const Ctor = [].constructor.constructor;
|
|
110
|
+
const fn = new Ctor("return process");
|
|
111
|
+
fn();
|
|
112
|
+
`,
|
|
113
|
+
shouldBlock: true
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "Constructor.constructor escape via object",
|
|
117
|
+
code: `
|
|
118
|
+
const Ctor = ({}).constructor.constructor;
|
|
119
|
+
const fn = new Ctor("return process");
|
|
120
|
+
fn();
|
|
121
|
+
`,
|
|
122
|
+
shouldBlock: true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "Constructor.constructor escape via string",
|
|
126
|
+
code: `
|
|
127
|
+
const Ctor = "".constructor.constructor;
|
|
128
|
+
const fn = new Ctor("return process");
|
|
129
|
+
fn();
|
|
130
|
+
`,
|
|
131
|
+
shouldBlock: true
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: "getPrototypeOf escape",
|
|
135
|
+
code: `
|
|
136
|
+
const proto = Object.getPrototypeOf([]);
|
|
137
|
+
const Ctor = proto.constructor.constructor;
|
|
138
|
+
new Ctor("process.exit()")();
|
|
139
|
+
`,
|
|
140
|
+
shouldBlock: true
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: "Reflection getOwnPropertyDescriptor escape",
|
|
144
|
+
code: `
|
|
145
|
+
const desc = Object.getOwnPropertyDescriptor({}, "x");
|
|
146
|
+
desc.constructor.constructor("process.exit()")();
|
|
147
|
+
`,
|
|
148
|
+
shouldBlock: true
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: "__proto__ pollution",
|
|
152
|
+
code: `
|
|
153
|
+
const obj = {};
|
|
154
|
+
obj.__proto__.ESCAPED = true;
|
|
155
|
+
({}).ESCAPED;
|
|
156
|
+
`,
|
|
157
|
+
shouldBlock: true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "Safe: Basic arithmetic",
|
|
161
|
+
code: `
|
|
162
|
+
1 + 2 + 3;
|
|
163
|
+
`,
|
|
164
|
+
shouldBlock: false
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "Safe: Array operations",
|
|
168
|
+
code: `
|
|
169
|
+
const arr = [1, 2, 3];
|
|
170
|
+
arr.map(x => x * 2);
|
|
171
|
+
`,
|
|
172
|
+
shouldBlock: false
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "Safe: Object creation",
|
|
176
|
+
code: `
|
|
177
|
+
const obj = { a: 1, b: 2 };
|
|
178
|
+
Object.keys(obj);
|
|
179
|
+
`,
|
|
180
|
+
shouldBlock: false
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "Safe: JSON serialization",
|
|
184
|
+
code: `
|
|
185
|
+
JSON.stringify({ x: 1, y: 2 });
|
|
186
|
+
`,
|
|
187
|
+
shouldBlock: false
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "Safe: String operations",
|
|
191
|
+
code: `
|
|
192
|
+
"hello world".toUpperCase().split(" ");
|
|
193
|
+
`,
|
|
194
|
+
shouldBlock: false
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "Safe: Math operations",
|
|
198
|
+
code: `
|
|
199
|
+
Math.sqrt(16) + Math.PI;
|
|
200
|
+
`,
|
|
201
|
+
shouldBlock: false
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "Safe: Deterministic date",
|
|
205
|
+
code: `
|
|
206
|
+
const d = new Date();
|
|
207
|
+
d.getTime();
|
|
208
|
+
`,
|
|
209
|
+
shouldBlock: false
|
|
210
|
+
}
|
|
211
|
+
];
|
|
212
|
+
/**
|
|
213
|
+
* Check if a test result is correct
|
|
214
|
+
*/
|
|
215
|
+
export function checkTestResult(test, threw, timedOut) {
|
|
216
|
+
if (test.shouldBlock) {
|
|
217
|
+
// Dangerous code should either throw or timeout
|
|
218
|
+
return threw || timedOut;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Safe code should succeed without throwing
|
|
222
|
+
return !threw && !timedOut;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=test-corpus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-corpus.js","sourceRoot":"","sources":["../src/test-corpus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC;QACE,IAAI,EAAE,2CAA2C;QACjD,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,gDAAgD;QACtD,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,6BAA6B;QACnC,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,qBAAqB;QAC3B,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,6BAA6B;QACnC,IAAI,EAAE;;;;;KAKL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,8BAA8B;QACpC,IAAI,EAAE;;;;;;KAML;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,qBAAqB;QAC3B,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,0CAA0C;QAChD,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,2CAA2C;QACjD,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,2CAA2C;QACjD,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,4CAA4C;QAClD,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,IAAI;KAClB;IAED;QACE,IAAI,EAAE,qBAAqB;QAC3B,IAAI,EAAE;;;;KAIL;QACD,WAAW,EAAE,IAAI;KAClB;IACD;QACE,IAAI,EAAE,wBAAwB;QAC9B,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,KAAK;KACnB;IAED;QACE,IAAI,EAAE,wBAAwB;QAC9B,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,KAAK;KACnB;IAED;QACE,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,KAAK;KACnB;IAED;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,KAAK;KACnB;IAED;QACE,IAAI,EAAE,yBAAyB;QAC/B,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,KAAK;KACnB;IAED;QACE,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE;;KAEL;QACD,WAAW,EAAE,KAAK;KACnB;IAED;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE;;;KAGL;QACD,WAAW,EAAE,KAAK;KACnB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAgB,EAAE,KAAc,EAAE,QAAiB;IACjF,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,gDAAgD;QAChD,OAAO,KAAK,IAAI,QAAQ,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,4CAA4C;QAC5C,OAAO,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CapabilityGrant } from "./capabilities.js";
|
|
2
|
+
import { StatsCollector } from "./stats.js";
|
|
3
|
+
import { PromiseTracker } from "./async.js";
|
|
4
|
+
/**
|
|
5
|
+
* Freeze all intrinsic constructors and their prototypes
|
|
6
|
+
* This prevents prototype poisoning attacks AND constructor.constructor escapes
|
|
7
|
+
*/
|
|
8
|
+
export declare function freezeIntrinsics(): void;
|
|
9
|
+
export declare function createSandboxScope(capabilities: CapabilityGrant, statsCollector: StatsCollector, promiseTracker: PromiseTracker, seed?: number): Record<string, unknown>;
|
|
10
|
+
export interface SandboxRuntimeOptions {
|
|
11
|
+
capabilities?: Partial<CapabilityGrant>;
|
|
12
|
+
seed?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Run code in a strict, isolated VM context with full tracking
|
|
16
|
+
*/
|
|
17
|
+
export declare function runInSandbox(code: string, options?: SandboxRuntimeOptions): Promise<{
|
|
18
|
+
result: unknown;
|
|
19
|
+
stats: StatsCollector;
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=vm-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm-runtime.d.ts","sourceRoot":"","sources":["../src/vm-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAA4B,MAAM,YAAY,CAAC;AAoDtE;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAsCvC;AAmED,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,eAAe,EAC7B,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,cAAc,EAC9B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6GzB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAC,CA6DrD"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import vm from "node:vm";
|
|
2
|
+
import { createCapabilityGrant, createCapabilityMembrane } from "./capabilities.js";
|
|
3
|
+
import { createDeterministicGlobals } from "./deterministic.js";
|
|
4
|
+
import { StatsCollector } from "./stats.js";
|
|
5
|
+
import { PromiseTracker, createPromiseInterceptor } from "./async.js";
|
|
6
|
+
/**
|
|
7
|
+
* Intrinsics that we want to lock down
|
|
8
|
+
* These are the core objects that malicious code could use to break out
|
|
9
|
+
*/
|
|
10
|
+
const INTRINSICS_TO_FREEZE = [
|
|
11
|
+
Object,
|
|
12
|
+
Array,
|
|
13
|
+
Function,
|
|
14
|
+
Promise,
|
|
15
|
+
Map,
|
|
16
|
+
Set,
|
|
17
|
+
WeakMap,
|
|
18
|
+
WeakSet,
|
|
19
|
+
Date,
|
|
20
|
+
RegExp,
|
|
21
|
+
Error,
|
|
22
|
+
TypeError,
|
|
23
|
+
ReferenceError,
|
|
24
|
+
SyntaxError,
|
|
25
|
+
RangeError
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Recursively freeze an object and all its properties
|
|
29
|
+
* Prevents any modification of the prototype chain
|
|
30
|
+
*/
|
|
31
|
+
function deepFreeze(obj, visited = new WeakSet()) {
|
|
32
|
+
if (obj === null || typeof obj !== "object")
|
|
33
|
+
return;
|
|
34
|
+
if (visited.has(obj))
|
|
35
|
+
return;
|
|
36
|
+
visited.add(obj);
|
|
37
|
+
Object.freeze(obj);
|
|
38
|
+
// Freeze all properties
|
|
39
|
+
for (const prop of Object.getOwnPropertyNames(obj)) {
|
|
40
|
+
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
|
|
41
|
+
if (descriptor && descriptor.value) {
|
|
42
|
+
deepFreeze(descriptor.value, visited);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Freeze symbol properties too
|
|
46
|
+
for (const sym of Object.getOwnPropertySymbols(obj)) {
|
|
47
|
+
const descriptor = Object.getOwnPropertyDescriptor(obj, sym);
|
|
48
|
+
if (descriptor && descriptor.value) {
|
|
49
|
+
deepFreeze(descriptor.value, visited);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Freeze all intrinsic constructors and their prototypes
|
|
55
|
+
* This prevents prototype poisoning attacks AND constructor.constructor escapes
|
|
56
|
+
*/
|
|
57
|
+
export function freezeIntrinsics() {
|
|
58
|
+
// Freeze each intrinsic deeply
|
|
59
|
+
for (const intrinsic of INTRINSICS_TO_FREEZE) {
|
|
60
|
+
deepFreeze(intrinsic);
|
|
61
|
+
deepFreeze(intrinsic.prototype);
|
|
62
|
+
}
|
|
63
|
+
// Block .constructor access on all prototype chains
|
|
64
|
+
const blockConstructor = (proto) => {
|
|
65
|
+
if (proto === null || typeof proto !== "object")
|
|
66
|
+
return;
|
|
67
|
+
try {
|
|
68
|
+
Object.defineProperty(proto, "constructor", {
|
|
69
|
+
value: undefined,
|
|
70
|
+
writable: false,
|
|
71
|
+
enumerable: false,
|
|
72
|
+
configurable: false
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch { }
|
|
76
|
+
};
|
|
77
|
+
// Block on all prototypes
|
|
78
|
+
for (const intrinsic of INTRINSICS_TO_FREEZE) {
|
|
79
|
+
blockConstructor(intrinsic.prototype);
|
|
80
|
+
blockConstructor(Object.getPrototypeOf(intrinsic));
|
|
81
|
+
}
|
|
82
|
+
// Freeze Object static methods that could be used to escape
|
|
83
|
+
Object.freeze(Object.getPrototypeOf);
|
|
84
|
+
Object.freeze(Object.getOwnPropertyDescriptor);
|
|
85
|
+
Object.freeze(Object.getOwnPropertyNames);
|
|
86
|
+
Object.freeze(Object.keys);
|
|
87
|
+
Object.freeze(Object.values);
|
|
88
|
+
Object.freeze(Object.entries);
|
|
89
|
+
// Block Reflect API if available
|
|
90
|
+
if (typeof Reflect !== "undefined") {
|
|
91
|
+
Object.freeze(Reflect);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create a Proxy handler that blocks dangerous property access
|
|
96
|
+
* Prevents constructor.constructor and __proto__ escapes
|
|
97
|
+
*/
|
|
98
|
+
function createConstructorBlockingProxy(target) {
|
|
99
|
+
return new Proxy(target, {
|
|
100
|
+
get(obj, prop, receiver) {
|
|
101
|
+
// Block constructor property
|
|
102
|
+
if (prop === "constructor" ||
|
|
103
|
+
prop === "__proto__" ||
|
|
104
|
+
prop === "__constructor") {
|
|
105
|
+
throw new Error(`Access to property '${String(prop)}' is forbidden`);
|
|
106
|
+
}
|
|
107
|
+
// Block dangerous reflection methods
|
|
108
|
+
if (prop === "getPrototypeOf" ||
|
|
109
|
+
prop === "setPrototypeOf" ||
|
|
110
|
+
prop === "getOwnPropertyDescriptor" ||
|
|
111
|
+
prop === "getOwnPropertyNames" ||
|
|
112
|
+
prop === "getOwnPropertySymbols") {
|
|
113
|
+
throw new Error(`Access to reflection method '${String(prop)}' is forbidden`);
|
|
114
|
+
}
|
|
115
|
+
return Reflect.get(obj, prop, receiver);
|
|
116
|
+
},
|
|
117
|
+
set(obj, prop, value) {
|
|
118
|
+
if (prop === "constructor" || prop === "__proto__") {
|
|
119
|
+
throw new Error(`Cannot assign to property '${String(prop)}'`);
|
|
120
|
+
}
|
|
121
|
+
return false; // Reject all writes
|
|
122
|
+
},
|
|
123
|
+
has(obj, prop) {
|
|
124
|
+
if (prop === "constructor" || prop === "__proto__") {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return Reflect.has(obj, prop);
|
|
128
|
+
},
|
|
129
|
+
ownKeys(obj) {
|
|
130
|
+
return Reflect.ownKeys(obj).filter((key) => key !== "constructor" && key !== "__proto__");
|
|
131
|
+
},
|
|
132
|
+
getOwnPropertyDescriptor(obj, prop) {
|
|
133
|
+
if (prop === "constructor" || prop === "__proto__") {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
return Reflect.getOwnPropertyDescriptor(obj, prop);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
export function createSandboxScope(capabilities, statsCollector, promiseTracker, seed) {
|
|
141
|
+
const deterministicGlobals = createDeterministicGlobals(seed);
|
|
142
|
+
const sandbox = Object.create(null, {
|
|
143
|
+
// Safe console (captured, no actual I/O)
|
|
144
|
+
console: {
|
|
145
|
+
value: createCapabilityMembrane({
|
|
146
|
+
log: (..._args) => {
|
|
147
|
+
// no-op: prevent information leakage
|
|
148
|
+
},
|
|
149
|
+
error: (..._args) => {
|
|
150
|
+
// no-op
|
|
151
|
+
},
|
|
152
|
+
warn: (..._args) => {
|
|
153
|
+
// no-op
|
|
154
|
+
},
|
|
155
|
+
info: (..._args) => {
|
|
156
|
+
// no-op
|
|
157
|
+
},
|
|
158
|
+
debug: (..._args) => {
|
|
159
|
+
// no-op
|
|
160
|
+
}
|
|
161
|
+
}, "console", capabilities.console),
|
|
162
|
+
writable: false,
|
|
163
|
+
enumerable: true
|
|
164
|
+
},
|
|
165
|
+
// Deterministic date
|
|
166
|
+
Date: {
|
|
167
|
+
value: createCapabilityMembrane(deterministicGlobals.Date, "date", capabilities.date),
|
|
168
|
+
writable: false,
|
|
169
|
+
enumerable: true
|
|
170
|
+
},
|
|
171
|
+
// Safe Math (no random)
|
|
172
|
+
Math: {
|
|
173
|
+
value: createCapabilityMembrane(deterministicGlobals.Math, "math", capabilities.math),
|
|
174
|
+
writable: false,
|
|
175
|
+
enumerable: true
|
|
176
|
+
},
|
|
177
|
+
// Safe JSON
|
|
178
|
+
JSON: {
|
|
179
|
+
value: createCapabilityMembrane(deterministicGlobals.JSON, "json", capabilities.json),
|
|
180
|
+
writable: false,
|
|
181
|
+
enumerable: true
|
|
182
|
+
},
|
|
183
|
+
// Promise with tracking
|
|
184
|
+
Promise: {
|
|
185
|
+
value: createPromiseInterceptor(promiseTracker),
|
|
186
|
+
writable: false,
|
|
187
|
+
enumerable: true
|
|
188
|
+
},
|
|
189
|
+
// Safe undefined (can't be shadowed)
|
|
190
|
+
undefined: {
|
|
191
|
+
value: undefined,
|
|
192
|
+
writable: false,
|
|
193
|
+
enumerable: true
|
|
194
|
+
},
|
|
195
|
+
// Stats collector hook
|
|
196
|
+
__STATS__: {
|
|
197
|
+
value: statsCollector,
|
|
198
|
+
writable: false,
|
|
199
|
+
enumerable: false
|
|
200
|
+
},
|
|
201
|
+
// Deterministic seed function (if enabled)
|
|
202
|
+
__SEED__: {
|
|
203
|
+
value: deterministicGlobals.Math_random,
|
|
204
|
+
writable: false,
|
|
205
|
+
enumerable: false
|
|
206
|
+
},
|
|
207
|
+
// Block reflection APIs
|
|
208
|
+
Object: {
|
|
209
|
+
value: createConstructorBlockingProxy(Object),
|
|
210
|
+
writable: false,
|
|
211
|
+
enumerable: true
|
|
212
|
+
},
|
|
213
|
+
// Remove Reflect if available
|
|
214
|
+
Reflect: {
|
|
215
|
+
value: createConstructorBlockingProxy(Reflect || {}),
|
|
216
|
+
writable: false,
|
|
217
|
+
enumerable: false
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
// Lock down the sandbox object itself
|
|
221
|
+
return Object.freeze(sandbox);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Run code in a strict, isolated VM context with full tracking
|
|
225
|
+
*/
|
|
226
|
+
export async function runInSandbox(code, options = {}) {
|
|
227
|
+
const stats = new StatsCollector();
|
|
228
|
+
stats.start();
|
|
229
|
+
try {
|
|
230
|
+
// Step 1: Freeze intrinsics FIRST, before creating context
|
|
231
|
+
freezeIntrinsics();
|
|
232
|
+
const capabilities = createCapabilityGrant(options.capabilities);
|
|
233
|
+
const promiseTracker = new PromiseTracker();
|
|
234
|
+
// Step 2: Build sandbox scope with capabilities and tracking
|
|
235
|
+
const sandbox = createSandboxScope(capabilities, stats, promiseTracker, options.seed);
|
|
236
|
+
// Step 3: Create VM context with strict settings
|
|
237
|
+
const context = vm.createContext(sandbox, {
|
|
238
|
+
name: "node-sandbox",
|
|
239
|
+
codeGeneration: {
|
|
240
|
+
strings: false, // No eval, Function constructor
|
|
241
|
+
wasm: false // No WebAssembly
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
// Step 4: Wrap user code in strict mode
|
|
245
|
+
const wrapped = `
|
|
246
|
+
"use strict";
|
|
247
|
+
(async () => {
|
|
248
|
+
return (${code});
|
|
249
|
+
})();
|
|
250
|
+
`;
|
|
251
|
+
// Step 5: Compile and execute
|
|
252
|
+
const script = new vm.Script(wrapped, {
|
|
253
|
+
filename: "sandboxed.js",
|
|
254
|
+
lineOffset: 0,
|
|
255
|
+
columnOffset: 0
|
|
256
|
+
});
|
|
257
|
+
// Extra safety timeout (main limit is in main thread)
|
|
258
|
+
const result = await script.runInContext(context, {
|
|
259
|
+
timeout: 10000, // 10 second internal timeout
|
|
260
|
+
displayErrors: true,
|
|
261
|
+
breakOnSigint: true
|
|
262
|
+
});
|
|
263
|
+
// Wait for all promises to settle
|
|
264
|
+
await promiseTracker.waitForAll(5000);
|
|
265
|
+
stats.markCompleted();
|
|
266
|
+
return { result, stats };
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
stats.recordError(err instanceof Error ? err.message : String(err));
|
|
270
|
+
throw err;
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
stats.updateMemory();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=vm-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm-runtime.js","sourceRoot":"","sources":["../src/vm-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker thread pool for reusing workers
|
|
3
|
+
* Dramatically reduces memory and spawn overhead
|
|
4
|
+
*/
|
|
5
|
+
import { Worker } from "node:worker_threads";
|
|
6
|
+
export interface PooledWorker {
|
|
7
|
+
worker: Worker;
|
|
8
|
+
busy: boolean;
|
|
9
|
+
lastUsed: number;
|
|
10
|
+
}
|
|
11
|
+
export interface PoolConfig {
|
|
12
|
+
minWorkers: number;
|
|
13
|
+
maxWorkers: number;
|
|
14
|
+
idleTimeout: number;
|
|
15
|
+
memoryMb: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class WorkerPool {
|
|
18
|
+
private workers;
|
|
19
|
+
private waitQueue;
|
|
20
|
+
private config;
|
|
21
|
+
constructor(config: PoolConfig);
|
|
22
|
+
private createPooledWorker;
|
|
23
|
+
/**
|
|
24
|
+
* Get an available worker from the pool
|
|
25
|
+
*/
|
|
26
|
+
acquire(): Promise<Worker>;
|
|
27
|
+
/**
|
|
28
|
+
* Release worker back to pool
|
|
29
|
+
*/
|
|
30
|
+
release(worker: Worker): void;
|
|
31
|
+
/**
|
|
32
|
+
* Clean up idle workers
|
|
33
|
+
*/
|
|
34
|
+
cleanup(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Terminate all workers
|
|
37
|
+
*/
|
|
38
|
+
destroy(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Get pool stats
|
|
41
|
+
*/
|
|
42
|
+
stats(): PoolStats;
|
|
43
|
+
}
|
|
44
|
+
export interface PoolStats {
|
|
45
|
+
totalWorkers: number;
|
|
46
|
+
busyWorkers: number;
|
|
47
|
+
idleWorkers: number;
|
|
48
|
+
waitingRequests: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Default pool configuration
|
|
52
|
+
*/
|
|
53
|
+
export declare const DEFAULT_POOL_CONFIG: PoolConfig;
|
|
54
|
+
/**
|
|
55
|
+
* High-concurrency configuration
|
|
56
|
+
*/
|
|
57
|
+
export declare const HIGH_CONCURRENCY_CONFIG: PoolConfig;
|
|
58
|
+
/**
|
|
59
|
+
* Low-resource configuration
|
|
60
|
+
*/
|
|
61
|
+
export declare const LOW_RESOURCE_CONFIG: PoolConfig;
|
|
62
|
+
//# sourceMappingURL=worker-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../src/worker-pool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAO7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,SAAS,CAGT;IACR,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,UAAU;IAQ9B,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IA4BhC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAgB7B;;OAEG;IACH,OAAO,IAAI,IAAI;IAsBf;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;OAEG;IACH,KAAK,IAAI,SAAS;CAQnB;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAKjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,UAKrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAKjC,CAAC"}
|