| title | Node.js System Driver |
|---|---|
| sidebarTitle | Node.js |
| description | Server-side system driver with full host capabilities. |
| icon | node-js |
The Node system driver provides sandboxed code with access to the host filesystem, networking, child processes, and environment. All capabilities sit behind a permission layer.
With no options, the driver provides a filesystem with a read-only node_modules overlay and no network or child process access.
import { createNodeDriver } from "secure-exec";
const driver = createNodeDriver();Pass options to enable and configure specific host capabilities.
import {
createNodeDriver,
createDefaultNetworkAdapter,
allowAllFs,
allowAllNetwork,
} from "secure-exec";
const driver = createNodeDriver({
useDefaultNetwork: true,
permissions: {
fs: allowAllFs,
network: allowAllNetwork,
},
processConfig: {
cwd: "/app",
env: { NODE_ENV: "production" },
},
});| Option | Type | Description |
|---|---|---|
filesystem |
VirtualFileSystem |
Custom filesystem implementation. Falls back to the built-in ModuleAccessFileSystem. |
moduleAccess |
ModuleAccessOptions |
Configure the node_modules overlay (see Module access). |
networkAdapter |
NetworkAdapter |
Custom network adapter. |
commandExecutor |
CommandExecutor |
Custom command executor for child processes (see Child processes). |
permissions |
Permissions |
Permission callbacks for fs, network, child process, and env access. |
useDefaultNetwork |
boolean |
Use the built-in network adapter (fetch, DNS, HTTP client). |
loopbackExemptPorts |
number[] |
Loopback ports that bypass SSRF checks when using the default network adapter. |
processConfig |
ProcessConfig |
Values for process.cwd(), process.env, etc. inside the sandbox. |
osConfig |
OSConfig |
Values for os.platform(), os.arch(), etc. inside the sandbox. |
Permissions are deny-by-default. Each capability (filesystem, network, child process, env) is controlled by a function that receives a request object and returns a PermissionDecision.
Each permission callback receives a typed request and returns { allow: boolean, reason?: string }.
import type {
FsAccessRequest,
NetworkAccessRequest,
ChildProcessAccessRequest,
EnvAccessRequest,
PermissionDecision,
} from "secure-exec";
const driver = createNodeDriver({
permissions: {
fs: (request: FsAccessRequest): PermissionDecision => {
if (request.path.startsWith("/tmp")) return { allow: true };
return { allow: false, reason: "Only /tmp is writable" };
},
network: (request: NetworkAccessRequest): PermissionDecision => {
if (request.hostname === "api.example.com") return { allow: true };
return { allow: false };
},
childProcess: (request: ChildProcessAccessRequest): PermissionDecision => {
if (request.command === "ls") return { allow: true };
return { allow: false, reason: `Blocked command: ${request.command}` };
},
env: (request: EnvAccessRequest): PermissionDecision => {
if (["NODE_ENV", "PATH"].includes(request.key)) return { allow: true };
return { allow: false };
},
},
});| Permission | Request fields |
|---|---|
fs |
op ("read", "write", "mkdir", "stat", "rm", "rename", ...), path |
network |
op ("fetch", "http", "dns", "listen"), url?, method?, hostname? |
childProcess |
command, args, cwd?, env? |
env |
op ("read", "write"), key, value? |
For development or trusted environments, use the built-in helpers.
import { allowAllFs, allowAllNetwork, allowAllChildProcess, allowAllEnv, allowAll } from "secure-exec";
const driver = createNodeDriver({
permissions: { ...allowAllFs, ...allowAllNetwork },
});
// Or allow everything:
const permissive = createNodeDriver({ permissions: allowAll });By default, the driver uses ModuleAccessFileSystem, which provides a read-only overlay of the host's node_modules. You can supply a custom VirtualFileSystem implementation or use the built-in in-memory filesystem.
import { createNodeDriver, createInMemoryFileSystem } from "secure-exec";
const fs = createInMemoryFileSystem();
await fs.writeFile("/app/data.json", '{"key": "value"}');
const driver = createNodeDriver({ filesystem: fs });The moduleAccess option configures which host node_modules directory is projected into the sandbox as a read-only overlay. By default it uses process.cwd() to locate node_modules.
const driver = createNodeDriver({
moduleAccess: {
cwd: "/path/to/your/project",
},
});| Option | Type | Description |
|---|---|---|
cwd |
string |
Absolute path used to resolve node_modules. Defaults to process.cwd(). |
Inside the sandbox, modules appear at /root/node_modules/... and are read-only. Write operations to the overlay throw EACCES. Native .node addons are rejected.
Provide a CommandExecutor to allow sandboxed code to spawn processes. This is gated behind the childProcess permission.
interface SpawnedProcess {
writeStdin(data: Uint8Array | string): void;
closeStdin(): void;
kill(signal?: number): void;
wait(): Promise<number>;
}
interface CommandExecutor {
spawn(
command: string,
args: string[],
options: {
cwd?: string;
env?: Record<string, string>;
onStdout?: (data: Uint8Array) => void;
onStderr?: (data: Uint8Array) => void;
},
): SpawnedProcess;
}import { spawn } from "node:child_process";
import type { CommandExecutor } from "secure-exec";
const commandExecutor: CommandExecutor = {
spawn(command, args, options) {
const proc = spawn(command, args, {
cwd: options.cwd,
env: options.env,
});
proc.stdout?.on("data", (chunk) => options.onStdout?.(chunk));
proc.stderr?.on("data", (chunk) => options.onStderr?.(chunk));
return {
writeStdin: (data) => proc.stdin?.write(data),
closeStdin: () => proc.stdin?.end(),
kill: (signal) => proc.kill(signal),
wait: () =>
new Promise((resolve) =>
proc.on("close", (code) => resolve(code ?? 1)),
),
};
},
};
const driver = createNodeDriver({
commandExecutor,
permissions: {
childProcess: (req) => {
if (req.command === "node") return { allow: true };
return { allow: false };
},
},
});Use processConfig and osConfig to control what the sandbox sees for process.cwd(), process.env, os.platform(), and similar APIs.
const driver = createNodeDriver({
processConfig: {
cwd: "/app",
env: { NODE_ENV: "production", API_KEY: "sk-..." },
},
osConfig: {
platform: "linux",
arch: "x64",
},
});