@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.
@@ -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 && _moduleCache[name]) {
309
+ if (!isRelative && __internalModuleCache[name]) {
310
310
  _debugRequire("cache-hit", name, name);
311
- return _moduleCache[name];
311
+ return __internalModuleCache[name];
312
312
  }
313
313
  if (name === "fs") {
314
- if (_moduleCache["fs"]) return _moduleCache["fs"];
314
+ if (__internalModuleCache["fs"]) return __internalModuleCache["fs"];
315
315
  const fsModule = globalThis.bridge?.fs || globalThis.bridge?.default || globalThis._fsModule || {};
316
- _moduleCache["fs"] = fsModule;
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 (_moduleCache["fs/promises"]) return _moduleCache["fs/promises"];
321
+ if (__internalModuleCache["fs/promises"]) return __internalModuleCache["fs/promises"];
322
322
  const fsModule = _requireFrom("fs", fromDir);
323
- _moduleCache["fs/promises"] = fsModule.promises;
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 (_moduleCache["stream/promises"]) return _moduleCache["stream/promises"];
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
- _moduleCache["stream/promises"] = promisesModule;
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 (_moduleCache["child_process"]) return _moduleCache["child_process"];
380
- _moduleCache["child_process"] = _childProcessModule;
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 (_moduleCache["http"]) return _moduleCache["http"];
386
- _moduleCache["http"] = _httpModule;
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 (_moduleCache["https"]) return _moduleCache["https"];
392
- _moduleCache["https"] = _httpsModule;
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 (_moduleCache["http2"]) return _moduleCache["http2"];
398
- _moduleCache["http2"] = _http2Module;
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 (_moduleCache["dns"]) return _moduleCache["dns"];
404
- _moduleCache["dns"] = _dnsModule;
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 (_moduleCache["os"]) return _moduleCache["os"];
410
- _moduleCache["os"] = _osModule;
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 (_moduleCache["module"]) return _moduleCache["module"];
416
- _moduleCache["module"] = _moduleModule;
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 (_moduleCache["async_hooks"]) return _moduleCache["async_hooks"];
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
- _moduleCache["async_hooks"] = asyncHooksModule;
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 (_moduleCache[name]) return _moduleCache[name];
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
- _moduleCache[name] = dcModule;
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 (_moduleCache[name]) return _moduleCache[name];
543
+ if (__internalModuleCache[name]) return __internalModuleCache[name];
544
544
  const deferredStub = _createDeferredModuleStub(name);
545
- _moduleCache[name] = deferredStub;
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 (_moduleCache[name]) return _moduleCache[name];
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
- _moduleCache[name] = moduleObj.exports;
564
+ __internalModuleCache[name] = moduleObj.exports;
565
565
  delete _pendingModules[name];
566
566
  _debugRequire("loaded", name, "polyfill");
567
- return _moduleCache[name];
567
+ return __internalModuleCache[name];
568
568
  }
569
569
  resolved = _resolveFrom(name, fromDir);
570
570
  cacheKey = resolved;
571
- if (_moduleCache[cacheKey]) {
571
+ if (__internalModuleCache[cacheKey]) {
572
572
  _debugRequire("cache-hit", name, cacheKey);
573
- return _moduleCache[cacheKey];
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
- _moduleCache[cacheKey] = parsed;
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
- _moduleCache[cacheKey] = module.exports;
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
  })();
@@ -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: "mutable-runtime-state",
301
- rationale: "Per-execution CommonJS/require cache state.",
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
- checkPermission(permissions?.fs, { op: "read", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
113
+ checkFs("read", path);
84
114
  return fs.readFile(path);
85
115
  },
86
116
  readTextFile: async (path) => {
87
- checkPermission(permissions?.fs, { op: "read", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
117
+ checkFs("read", path);
88
118
  return fs.readTextFile(path);
89
119
  },
90
120
  readDir: async (path) => {
91
- checkPermission(permissions?.fs, { op: "readdir", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
121
+ checkFs("readdir", path);
92
122
  return fs.readDir(path);
93
123
  },
94
124
  readDirWithTypes: async (path) => {
95
- checkPermission(permissions?.fs, { op: "readdir", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
125
+ checkFs("readdir", path);
96
126
  return fs.readDirWithTypes(path);
97
127
  },
98
128
  writeFile: async (path, content) => {
99
- checkPermission(permissions?.fs, { op: "write", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
129
+ checkFs("write", path);
100
130
  return fs.writeFile(path, content);
101
131
  },
102
132
  createDir: async (path) => {
103
- checkPermission(permissions?.fs, { op: "createDir", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
133
+ checkFs("createDir", path);
104
134
  return fs.createDir(path);
105
135
  },
106
136
  mkdir: async (path) => {
107
- checkPermission(permissions?.fs, { op: "mkdir", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
137
+ checkFs("mkdir", path);
108
138
  return fs.mkdir(path);
109
139
  },
110
140
  exists: async (path) => {
111
- checkPermission(permissions?.fs, { op: "exists", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
141
+ checkFs("exists", path);
112
142
  return fs.exists(path);
113
143
  },
114
144
  stat: async (path) => {
115
- checkPermission(permissions?.fs, { op: "stat", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
145
+ checkFs("stat", path);
116
146
  return fs.stat(path);
117
147
  },
118
148
  removeFile: async (path) => {
119
- checkPermission(permissions?.fs, { op: "rm", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
149
+ checkFs("rm", path);
120
150
  return fs.removeFile(path);
121
151
  },
122
152
  removeDir: async (path) => {
123
- checkPermission(permissions?.fs, { op: "rm", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
153
+ checkFs("rm", path);
124
154
  return fs.removeDir(path);
125
155
  },
126
156
  rename: async (oldPath, newPath) => {
127
- checkPermission(permissions?.fs, { op: "rename", path: oldPath }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
128
- checkPermission(permissions?.fs, { op: "rename", path: newPath }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
157
+ checkFs("rename", oldPath);
158
+ checkFs("rename", newPath);
129
159
  return fs.rename(oldPath, newPath);
130
160
  },
131
161
  symlink: async (target, linkPath) => {
132
- checkPermission(permissions?.fs, { op: "symlink", path: linkPath }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
162
+ checkFs("symlink", linkPath);
133
163
  return fs.symlink(target, linkPath);
134
164
  },
135
165
  readlink: async (path) => {
136
- checkPermission(permissions?.fs, { op: "readlink", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
166
+ checkFs("readlink", path);
137
167
  return fs.readlink(path);
138
168
  },
139
169
  lstat: async (path) => {
140
- checkPermission(permissions?.fs, { op: "stat", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
170
+ checkFs("stat", path);
141
171
  return fs.lstat(path);
142
172
  },
143
173
  link: async (oldPath, newPath) => {
144
- checkPermission(permissions?.fs, { op: "link", path: newPath }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
174
+ checkFs("link", newPath);
145
175
  return fs.link(oldPath, newPath);
146
176
  },
147
177
  chmod: async (path, mode) => {
148
- checkPermission(permissions?.fs, { op: "chmod", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
178
+ checkFs("chmod", path);
149
179
  return fs.chmod(path, mode);
150
180
  },
151
181
  chown: async (path, uid, gid) => {
152
- checkPermission(permissions?.fs, { op: "chown", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
182
+ checkFs("chown", path);
153
183
  return fs.chown(path, uid, gid);
154
184
  },
155
185
  utimes: async (path, atime, mtime) => {
156
- checkPermission(permissions?.fs, { op: "utimes", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
186
+ checkFs("utimes", path);
157
187
  return fs.utimes(path, atime, mtime);
158
188
  },
159
189
  truncate: async (path, length) => {
160
- checkPermission(permissions?.fs, { op: "truncate", path }, (req, reason) => createEaccesError(fsOpToSyscall(req.op), req.path, reason));
190
+ checkFs("truncate", path);
161
191
  return fs.truncate(path, length);
162
192
  },
163
193
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secure-exec/core",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.0-rc.3",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",