Documentation Index
Fetch the complete documentation index at: https://secureexec.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
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.
Basic setup
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();
Configuring capabilities
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" },
},
});
All options
| 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
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.
Function-based permissions
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 };
},
},
});
Request types
| 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? |
Allow-all helpers
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 });
Filesystem
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 });
Module access
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.
Child processes
Provide a CommandExecutor to allow sandboxed code to spawn processes. This is gated behind the childProcess permission.
CommandExecutor interface
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;
}
Custom executor example
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 };
},
},
});
Process and OS configuration
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",
},
});