Example on GitHub
Runnable example for child process spawning.
Sandboxed code can spawn child processes through the CommandExecutor interface, gated by the childProcess permission.
Runnable example
import {
NodeRuntime,
allowAllChildProcess,
createNodeDriver,
createNodeRuntimeDriverFactory,
type CommandExecutor,
} from "../../../packages/secure-exec/src/index.ts";
import { spawn } from "node:child_process";
const commandExecutor: CommandExecutor = {
spawn(command, args, options) {
const resolvedCommand = command === "node" ? process.execPath : command;
const resolvedCwd = options.cwd === "/root" ? process.cwd() : options.cwd;
const child = spawn(resolvedCommand, args, {
cwd: resolvedCwd,
env: options.env,
stdio: ["pipe", "pipe", "pipe"],
});
child.stdout.on("data", (chunk) => {
options.onStdout?.(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
});
child.stderr.on("data", (chunk) => {
options.onStderr?.(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
});
return {
writeStdin(data) {
child.stdin.write(data);
},
closeStdin() {
child.stdin.end();
},
kill(signal) {
child.kill(signal);
},
wait() {
return new Promise<number>((resolve) => {
child.once("close", (code) => resolve(code ?? 1));
});
},
};
},
};
const runtime = new NodeRuntime({
systemDriver: createNodeDriver({
commandExecutor,
permissions: { ...allowAllChildProcess },
}),
runtimeDriverFactory: createNodeRuntimeDriverFactory(),
});
try {
const result = await runtime.exec(`
const { spawnSync } = require("node:child_process");
const child = spawnSync("node", ["--version"], {
encoding: "utf8",
});
const output =
typeof child.stdout === "string"
? child.stdout
: Buffer.from(child.stdout || []).toString("utf8");
if (child.status !== 0 || !output.startsWith("v")) {
throw new Error("Unexpected child process exit code: " + child.status);
}
`);
if (result.code !== 0) {
throw new Error(`Unexpected execution result: ${JSON.stringify(result)}`);
}
console.log(
JSON.stringify({
ok: true,
summary: "sandbox spawned node --version successfully",
}),
);
} finally {
runtime.dispose();
}
Source: examples/features/src/child-processes.ts
Permission gating
Restrict which commands sandboxed code can spawn:
const driver = createNodeDriver({
permissions: {
childProcess: (req) => {
const allowed = ["node", "python3", "echo"];
return { allow: allowed.includes(req.command) };
},
},
});
Custom CommandExecutor
Provide your own executor for full control over process spawning:
const driver = createNodeDriver({
commandExecutor: {
spawn(command, args, options) {
// Custom spawn logic
// Returns a SpawnedProcess
},
},
permissions: {
childProcess: () => ({ allow: true }),
},
});
Process configuration
Configure the process environment visible to sandboxed code:
const driver = createNodeDriver({
processConfig: {
cwd: "/app",
env: { NODE_ENV: "production" },
argv: ["node", "script.js"],
platform: "linux",
arch: "x64",
},
});
Child processes are only available with the Node system driver. The browser driver does not support process spawning.