@secure-exec/core 0.1.0-rc.2 → 0.1.0-rc.3
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/dist/bridge/active-handles.d.ts +1 -0
- package/dist/bridge/active-handles.js +5 -10
- package/dist/bridge/child-process.d.ts +9 -0
- package/dist/bridge/child-process.js +71 -7
- package/dist/bridge/fs.js +96 -12
- package/dist/bridge/network.js +7 -7
- package/dist/bridge/process.js +72 -34
- package/dist/bridge.js +264 -53
- package/dist/generated/isolate-runtime.d.ts +3 -3
- package/dist/generated/isolate-runtime.js +3 -3
- package/dist/isolate-runtime/apply-timing-mitigation-freeze.js +102 -18
- package/dist/isolate-runtime/bridge-initial-globals.js +2 -2
- package/dist/isolate-runtime/require-setup.js +72 -36
- package/dist/runtime-driver.d.ts +2 -0
- package/dist/shared/global-exposure.js +27 -2
- package/dist/shared/permissions.js +51 -21
- package/package.json +1 -1
|
@@ -270,6 +270,7 @@
|
|
|
270
270
|
});
|
|
271
271
|
return stub;
|
|
272
272
|
}
|
|
273
|
+
var __internalModuleCache = _moduleCache;
|
|
273
274
|
var __require = function require2(moduleName2) {
|
|
274
275
|
return _requireFrom(moduleName2, _currentModule.dirname);
|
|
275
276
|
};
|
|
@@ -286,7 +287,6 @@
|
|
|
286
287
|
globalThis.require.resolve = function resolve(moduleName2) {
|
|
287
288
|
return _resolveFrom(moduleName2, _currentModule.dirname);
|
|
288
289
|
};
|
|
289
|
-
globalThis.require.cache = _moduleCache;
|
|
290
290
|
function _debugRequire(phase, moduleName2, extra) {
|
|
291
291
|
if (globalThis.__sandboxRequireDebug !== true) {
|
|
292
292
|
return;
|
|
@@ -306,26 +306,26 @@
|
|
|
306
306
|
let cacheKey = name;
|
|
307
307
|
let resolved = null;
|
|
308
308
|
const isRelative = name.startsWith("./") || name.startsWith("../");
|
|
309
|
-
if (!isRelative &&
|
|
309
|
+
if (!isRelative && __internalModuleCache[name]) {
|
|
310
310
|
_debugRequire("cache-hit", name, name);
|
|
311
|
-
return
|
|
311
|
+
return __internalModuleCache[name];
|
|
312
312
|
}
|
|
313
313
|
if (name === "fs") {
|
|
314
|
-
if (
|
|
314
|
+
if (__internalModuleCache["fs"]) return __internalModuleCache["fs"];
|
|
315
315
|
const fsModule = globalThis.bridge?.fs || globalThis.bridge?.default || globalThis._fsModule || {};
|
|
316
|
-
|
|
316
|
+
__internalModuleCache["fs"] = fsModule;
|
|
317
317
|
_debugRequire("loaded", name, "fs-special");
|
|
318
318
|
return fsModule;
|
|
319
319
|
}
|
|
320
320
|
if (name === "fs/promises") {
|
|
321
|
-
if (
|
|
321
|
+
if (__internalModuleCache["fs/promises"]) return __internalModuleCache["fs/promises"];
|
|
322
322
|
const fsModule = _requireFrom("fs", fromDir);
|
|
323
|
-
|
|
323
|
+
__internalModuleCache["fs/promises"] = fsModule.promises;
|
|
324
324
|
_debugRequire("loaded", name, "fs-promises-special");
|
|
325
325
|
return fsModule.promises;
|
|
326
326
|
}
|
|
327
327
|
if (name === "stream/promises") {
|
|
328
|
-
if (
|
|
328
|
+
if (__internalModuleCache["stream/promises"]) return __internalModuleCache["stream/promises"];
|
|
329
329
|
const streamModule = _requireFrom("stream", fromDir);
|
|
330
330
|
const promisesModule = {
|
|
331
331
|
finished(stream, options) {
|
|
@@ -371,49 +371,49 @@
|
|
|
371
371
|
});
|
|
372
372
|
}
|
|
373
373
|
};
|
|
374
|
-
|
|
374
|
+
__internalModuleCache["stream/promises"] = promisesModule;
|
|
375
375
|
_debugRequire("loaded", name, "stream-promises-special");
|
|
376
376
|
return promisesModule;
|
|
377
377
|
}
|
|
378
378
|
if (name === "child_process") {
|
|
379
|
-
if (
|
|
380
|
-
|
|
379
|
+
if (__internalModuleCache["child_process"]) return __internalModuleCache["child_process"];
|
|
380
|
+
__internalModuleCache["child_process"] = _childProcessModule;
|
|
381
381
|
_debugRequire("loaded", name, "child-process-special");
|
|
382
382
|
return _childProcessModule;
|
|
383
383
|
}
|
|
384
384
|
if (name === "http") {
|
|
385
|
-
if (
|
|
386
|
-
|
|
385
|
+
if (__internalModuleCache["http"]) return __internalModuleCache["http"];
|
|
386
|
+
__internalModuleCache["http"] = _httpModule;
|
|
387
387
|
_debugRequire("loaded", name, "http-special");
|
|
388
388
|
return _httpModule;
|
|
389
389
|
}
|
|
390
390
|
if (name === "https") {
|
|
391
|
-
if (
|
|
392
|
-
|
|
391
|
+
if (__internalModuleCache["https"]) return __internalModuleCache["https"];
|
|
392
|
+
__internalModuleCache["https"] = _httpsModule;
|
|
393
393
|
_debugRequire("loaded", name, "https-special");
|
|
394
394
|
return _httpsModule;
|
|
395
395
|
}
|
|
396
396
|
if (name === "http2") {
|
|
397
|
-
if (
|
|
398
|
-
|
|
397
|
+
if (__internalModuleCache["http2"]) return __internalModuleCache["http2"];
|
|
398
|
+
__internalModuleCache["http2"] = _http2Module;
|
|
399
399
|
_debugRequire("loaded", name, "http2-special");
|
|
400
400
|
return _http2Module;
|
|
401
401
|
}
|
|
402
402
|
if (name === "dns") {
|
|
403
|
-
if (
|
|
404
|
-
|
|
403
|
+
if (__internalModuleCache["dns"]) return __internalModuleCache["dns"];
|
|
404
|
+
__internalModuleCache["dns"] = _dnsModule;
|
|
405
405
|
_debugRequire("loaded", name, "dns-special");
|
|
406
406
|
return _dnsModule;
|
|
407
407
|
}
|
|
408
408
|
if (name === "os") {
|
|
409
|
-
if (
|
|
410
|
-
|
|
409
|
+
if (__internalModuleCache["os"]) return __internalModuleCache["os"];
|
|
410
|
+
__internalModuleCache["os"] = _osModule;
|
|
411
411
|
_debugRequire("loaded", name, "os-special");
|
|
412
412
|
return _osModule;
|
|
413
413
|
}
|
|
414
414
|
if (name === "module") {
|
|
415
|
-
if (
|
|
416
|
-
|
|
415
|
+
if (__internalModuleCache["module"]) return __internalModuleCache["module"];
|
|
416
|
+
__internalModuleCache["module"] = _moduleModule;
|
|
417
417
|
_debugRequire("loaded", name, "module-special");
|
|
418
418
|
return _moduleModule;
|
|
419
419
|
}
|
|
@@ -422,7 +422,7 @@
|
|
|
422
422
|
return globalThis.process;
|
|
423
423
|
}
|
|
424
424
|
if (name === "async_hooks") {
|
|
425
|
-
if (
|
|
425
|
+
if (__internalModuleCache["async_hooks"]) return __internalModuleCache["async_hooks"];
|
|
426
426
|
class AsyncLocalStorage {
|
|
427
427
|
constructor() {
|
|
428
428
|
this._store = void 0;
|
|
@@ -491,7 +491,7 @@
|
|
|
491
491
|
return null;
|
|
492
492
|
}
|
|
493
493
|
};
|
|
494
|
-
|
|
494
|
+
__internalModuleCache["async_hooks"] = asyncHooksModule;
|
|
495
495
|
_debugRequire("loaded", name, "async-hooks-special");
|
|
496
496
|
return asyncHooksModule;
|
|
497
497
|
}
|
|
@@ -508,7 +508,7 @@
|
|
|
508
508
|
};
|
|
509
509
|
};
|
|
510
510
|
var _createChannel = _createChannel2;
|
|
511
|
-
if (
|
|
511
|
+
if (__internalModuleCache[name]) return __internalModuleCache[name];
|
|
512
512
|
const dcModule = {
|
|
513
513
|
channel: function() {
|
|
514
514
|
return _createChannel2();
|
|
@@ -535,14 +535,14 @@
|
|
|
535
535
|
};
|
|
536
536
|
}
|
|
537
537
|
};
|
|
538
|
-
|
|
538
|
+
__internalModuleCache[name] = dcModule;
|
|
539
539
|
_debugRequire("loaded", name, "diagnostics-channel-special");
|
|
540
540
|
return dcModule;
|
|
541
541
|
}
|
|
542
542
|
if (_deferredCoreModules.has(name)) {
|
|
543
|
-
if (
|
|
543
|
+
if (__internalModuleCache[name]) return __internalModuleCache[name];
|
|
544
544
|
const deferredStub = _createDeferredModuleStub(name);
|
|
545
|
-
|
|
545
|
+
__internalModuleCache[name] = deferredStub;
|
|
546
546
|
_debugRequire("loaded", name, "deferred-stub");
|
|
547
547
|
return deferredStub;
|
|
548
548
|
}
|
|
@@ -551,7 +551,7 @@
|
|
|
551
551
|
}
|
|
552
552
|
const polyfillCode = _loadPolyfill.applySyncPromise(void 0, [name]);
|
|
553
553
|
if (polyfillCode !== null) {
|
|
554
|
-
if (
|
|
554
|
+
if (__internalModuleCache[name]) return __internalModuleCache[name];
|
|
555
555
|
const moduleObj = { exports: {} };
|
|
556
556
|
_pendingModules[name] = moduleObj;
|
|
557
557
|
let result = eval(polyfillCode);
|
|
@@ -561,16 +561,16 @@
|
|
|
561
561
|
} else {
|
|
562
562
|
moduleObj.exports = result;
|
|
563
563
|
}
|
|
564
|
-
|
|
564
|
+
__internalModuleCache[name] = moduleObj.exports;
|
|
565
565
|
delete _pendingModules[name];
|
|
566
566
|
_debugRequire("loaded", name, "polyfill");
|
|
567
|
-
return
|
|
567
|
+
return __internalModuleCache[name];
|
|
568
568
|
}
|
|
569
569
|
resolved = _resolveFrom(name, fromDir);
|
|
570
570
|
cacheKey = resolved;
|
|
571
|
-
if (
|
|
571
|
+
if (__internalModuleCache[cacheKey]) {
|
|
572
572
|
_debugRequire("cache-hit", name, cacheKey);
|
|
573
|
-
return
|
|
573
|
+
return __internalModuleCache[cacheKey];
|
|
574
574
|
}
|
|
575
575
|
if (_pendingModules[cacheKey]) {
|
|
576
576
|
_debugRequire("pending-hit", name, cacheKey);
|
|
@@ -584,7 +584,7 @@
|
|
|
584
584
|
}
|
|
585
585
|
if (resolved.endsWith(".json")) {
|
|
586
586
|
const parsed = JSON.parse(source);
|
|
587
|
-
|
|
587
|
+
__internalModuleCache[cacheKey] = parsed;
|
|
588
588
|
return parsed;
|
|
589
589
|
}
|
|
590
590
|
const normalizedSource = typeof source === "string" ? source.replace(/import\.meta\.url/g, "__filename").replace(/fileURLToPath\(__filename\)/g, "__filename").replace(/url\.fileURLToPath\(__filename\)/g, "__filename").replace(/fileURLToPath\.call\(void 0, __filename\)/g, "__filename") : source;
|
|
@@ -641,10 +641,46 @@
|
|
|
641
641
|
} finally {
|
|
642
642
|
_currentModule = prevModule;
|
|
643
643
|
}
|
|
644
|
-
|
|
644
|
+
__internalModuleCache[cacheKey] = module.exports;
|
|
645
645
|
delete _pendingModules[cacheKey];
|
|
646
646
|
_debugRequire("loaded", name, cacheKey);
|
|
647
647
|
return module.exports;
|
|
648
648
|
}
|
|
649
649
|
__requireExposeCustomGlobal("_requireFrom", _requireFrom);
|
|
650
|
+
var __moduleCacheProxy = new Proxy(__internalModuleCache, {
|
|
651
|
+
get(target, prop, receiver) {
|
|
652
|
+
return Reflect.get(target, prop, receiver);
|
|
653
|
+
},
|
|
654
|
+
set(_target, prop) {
|
|
655
|
+
throw new TypeError("Cannot set require.cache['" + String(prop) + "']");
|
|
656
|
+
},
|
|
657
|
+
deleteProperty(_target, prop) {
|
|
658
|
+
throw new TypeError("Cannot delete require.cache['" + String(prop) + "']");
|
|
659
|
+
},
|
|
660
|
+
defineProperty(_target, prop) {
|
|
661
|
+
throw new TypeError("Cannot define property '" + String(prop) + "' on require.cache");
|
|
662
|
+
},
|
|
663
|
+
has(target, prop) {
|
|
664
|
+
return Reflect.has(target, prop);
|
|
665
|
+
},
|
|
666
|
+
ownKeys(target) {
|
|
667
|
+
return Reflect.ownKeys(target);
|
|
668
|
+
},
|
|
669
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
670
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
globalThis.require.cache = __moduleCacheProxy;
|
|
674
|
+
Object.defineProperty(globalThis, "_moduleCache", {
|
|
675
|
+
value: __moduleCacheProxy,
|
|
676
|
+
writable: false,
|
|
677
|
+
configurable: true,
|
|
678
|
+
enumerable: false
|
|
679
|
+
});
|
|
680
|
+
if (typeof _moduleModule !== "undefined") {
|
|
681
|
+
if (_moduleModule.Module) {
|
|
682
|
+
_moduleModule.Module._cache = __moduleCacheProxy;
|
|
683
|
+
}
|
|
684
|
+
_moduleModule._cache = __moduleCacheProxy;
|
|
685
|
+
}
|
|
650
686
|
})();
|
package/dist/runtime-driver.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface ResourceBudgets {
|
|
|
13
13
|
maxTimers?: number;
|
|
14
14
|
/** Maximum child_process.spawn() invocations per execution. */
|
|
15
15
|
maxChildProcesses?: number;
|
|
16
|
+
/** Maximum concurrent active handles (child processes, timers, servers) in the bridge handle map. */
|
|
17
|
+
maxHandles?: number;
|
|
16
18
|
}
|
|
17
19
|
export interface RuntimeDriverOptions {
|
|
18
20
|
system: SystemDriver;
|
|
@@ -297,8 +297,8 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
297
297
|
},
|
|
298
298
|
{
|
|
299
299
|
name: "_moduleCache",
|
|
300
|
-
classification: "
|
|
301
|
-
rationale: "Per-execution CommonJS/require cache
|
|
300
|
+
classification: "hardened",
|
|
301
|
+
rationale: "Per-execution CommonJS/require cache — hardened via read-only Proxy to prevent cache poisoning.",
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
name: "_pendingModules",
|
|
@@ -350,6 +350,31 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
350
350
|
classification: "mutable-runtime-state",
|
|
351
351
|
rationale: "Per-execution CommonJS file context state.",
|
|
352
352
|
},
|
|
353
|
+
{
|
|
354
|
+
name: "fetch",
|
|
355
|
+
classification: "hardened",
|
|
356
|
+
rationale: "Network fetch API global — must not be replaceable by sandbox code.",
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: "Headers",
|
|
360
|
+
classification: "hardened",
|
|
361
|
+
rationale: "Network Headers API global — must not be replaceable by sandbox code.",
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "Request",
|
|
365
|
+
classification: "hardened",
|
|
366
|
+
rationale: "Network Request API global — must not be replaceable by sandbox code.",
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "Response",
|
|
370
|
+
classification: "hardened",
|
|
371
|
+
rationale: "Network Response API global — must not be replaceable by sandbox code.",
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: "Blob",
|
|
375
|
+
classification: "hardened",
|
|
376
|
+
rationale: "Blob API global stub — must not be replaceable by sandbox code.",
|
|
377
|
+
},
|
|
353
378
|
];
|
|
354
379
|
export const HARDENED_NODE_CUSTOM_GLOBALS = NODE_CUSTOM_GLOBAL_INVENTORY
|
|
355
380
|
.filter((entry) => entry.classification === "hardened")
|
|
@@ -6,6 +6,32 @@
|
|
|
6
6
|
* for a category, guarded operations in that category are denied by default.
|
|
7
7
|
*/
|
|
8
8
|
import { createEaccesError, createEnosysError } from "./errors.js";
|
|
9
|
+
/** Normalize a filesystem path: collapse //, resolve . and .., strip trailing /. */
|
|
10
|
+
function normalizeFsPath(path) {
|
|
11
|
+
// Collapse repeated slashes
|
|
12
|
+
let p = path.replace(/\/+/g, "/");
|
|
13
|
+
// Resolve . and .. segments
|
|
14
|
+
const parts = p.split("/");
|
|
15
|
+
const resolved = [];
|
|
16
|
+
for (const seg of parts) {
|
|
17
|
+
if (seg === ".")
|
|
18
|
+
continue;
|
|
19
|
+
if (seg === "..") {
|
|
20
|
+
// Don't pop past root
|
|
21
|
+
if (resolved.length > 1)
|
|
22
|
+
resolved.pop();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
resolved.push(seg);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
p = resolved.join("/") || "/";
|
|
29
|
+
// Strip trailing slash (except root)
|
|
30
|
+
if (p.length > 1 && p.endsWith("/")) {
|
|
31
|
+
p = p.slice(0, -1);
|
|
32
|
+
}
|
|
33
|
+
return p;
|
|
34
|
+
}
|
|
9
35
|
/** Run the permission check; throw the deny error if no checker exists or it denies. */
|
|
10
36
|
function checkPermission(check, request, onDenied) {
|
|
11
37
|
if (!check) {
|
|
@@ -78,86 +104,90 @@ function fsOpToSyscall(op) {
|
|
|
78
104
|
* Throws EACCES if the permission callback denies or is absent.
|
|
79
105
|
*/
|
|
80
106
|
export function wrapFileSystem(fs, permissions) {
|
|
107
|
+
/** Check fs permission with normalized path to prevent traversal bypasses. */
|
|
108
|
+
function checkFs(op, path, reason) {
|
|
109
|
+
checkPermission(permissions?.fs, { op, path: normalizeFsPath(path) }, (req, r) => createEaccesError(fsOpToSyscall(req.op), req.path, r));
|
|
110
|
+
}
|
|
81
111
|
return {
|
|
82
112
|
readFile: async (path) => {
|
|
83
|
-
|
|
113
|
+
checkFs("read", path);
|
|
84
114
|
return fs.readFile(path);
|
|
85
115
|
},
|
|
86
116
|
readTextFile: async (path) => {
|
|
87
|
-
|
|
117
|
+
checkFs("read", path);
|
|
88
118
|
return fs.readTextFile(path);
|
|
89
119
|
},
|
|
90
120
|
readDir: async (path) => {
|
|
91
|
-
|
|
121
|
+
checkFs("readdir", path);
|
|
92
122
|
return fs.readDir(path);
|
|
93
123
|
},
|
|
94
124
|
readDirWithTypes: async (path) => {
|
|
95
|
-
|
|
125
|
+
checkFs("readdir", path);
|
|
96
126
|
return fs.readDirWithTypes(path);
|
|
97
127
|
},
|
|
98
128
|
writeFile: async (path, content) => {
|
|
99
|
-
|
|
129
|
+
checkFs("write", path);
|
|
100
130
|
return fs.writeFile(path, content);
|
|
101
131
|
},
|
|
102
132
|
createDir: async (path) => {
|
|
103
|
-
|
|
133
|
+
checkFs("createDir", path);
|
|
104
134
|
return fs.createDir(path);
|
|
105
135
|
},
|
|
106
136
|
mkdir: async (path) => {
|
|
107
|
-
|
|
137
|
+
checkFs("mkdir", path);
|
|
108
138
|
return fs.mkdir(path);
|
|
109
139
|
},
|
|
110
140
|
exists: async (path) => {
|
|
111
|
-
|
|
141
|
+
checkFs("exists", path);
|
|
112
142
|
return fs.exists(path);
|
|
113
143
|
},
|
|
114
144
|
stat: async (path) => {
|
|
115
|
-
|
|
145
|
+
checkFs("stat", path);
|
|
116
146
|
return fs.stat(path);
|
|
117
147
|
},
|
|
118
148
|
removeFile: async (path) => {
|
|
119
|
-
|
|
149
|
+
checkFs("rm", path);
|
|
120
150
|
return fs.removeFile(path);
|
|
121
151
|
},
|
|
122
152
|
removeDir: async (path) => {
|
|
123
|
-
|
|
153
|
+
checkFs("rm", path);
|
|
124
154
|
return fs.removeDir(path);
|
|
125
155
|
},
|
|
126
156
|
rename: async (oldPath, newPath) => {
|
|
127
|
-
|
|
128
|
-
|
|
157
|
+
checkFs("rename", oldPath);
|
|
158
|
+
checkFs("rename", newPath);
|
|
129
159
|
return fs.rename(oldPath, newPath);
|
|
130
160
|
},
|
|
131
161
|
symlink: async (target, linkPath) => {
|
|
132
|
-
|
|
162
|
+
checkFs("symlink", linkPath);
|
|
133
163
|
return fs.symlink(target, linkPath);
|
|
134
164
|
},
|
|
135
165
|
readlink: async (path) => {
|
|
136
|
-
|
|
166
|
+
checkFs("readlink", path);
|
|
137
167
|
return fs.readlink(path);
|
|
138
168
|
},
|
|
139
169
|
lstat: async (path) => {
|
|
140
|
-
|
|
170
|
+
checkFs("stat", path);
|
|
141
171
|
return fs.lstat(path);
|
|
142
172
|
},
|
|
143
173
|
link: async (oldPath, newPath) => {
|
|
144
|
-
|
|
174
|
+
checkFs("link", newPath);
|
|
145
175
|
return fs.link(oldPath, newPath);
|
|
146
176
|
},
|
|
147
177
|
chmod: async (path, mode) => {
|
|
148
|
-
|
|
178
|
+
checkFs("chmod", path);
|
|
149
179
|
return fs.chmod(path, mode);
|
|
150
180
|
},
|
|
151
181
|
chown: async (path, uid, gid) => {
|
|
152
|
-
|
|
182
|
+
checkFs("chown", path);
|
|
153
183
|
return fs.chown(path, uid, gid);
|
|
154
184
|
},
|
|
155
185
|
utimes: async (path, atime, mtime) => {
|
|
156
|
-
|
|
186
|
+
checkFs("utimes", path);
|
|
157
187
|
return fs.utimes(path, atime, mtime);
|
|
158
188
|
},
|
|
159
189
|
truncate: async (path, length) => {
|
|
160
|
-
|
|
190
|
+
checkFs("truncate", path);
|
|
161
191
|
return fs.truncate(path, length);
|
|
162
192
|
},
|
|
163
193
|
};
|