UNPKG

@aikidosec/firewall

Version:

Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks

152 lines (151 loc) 5.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChildProcess = void 0; const Context_1 = require("../agent/Context"); const wrapExport_1 = require("../agent/hooks/wrapExport"); const isPlainObject_1 = require("../helpers/isPlainObject"); const checkContextForPathTraversal_1 = require("../vulnerabilities/path-traversal/checkContextForPathTraversal"); const checkContextForShellInjection_1 = require("../vulnerabilities/shell-injection/checkContextForShellInjection"); const PATH_PREFIXES = [ "/bin/", "/sbin/", "/usr/bin/", "/usr/sbin/", "/usr/local/bin/", "/usr/local/sbin/", ]; class ChildProcess { wrap(hooks) { hooks.addBuiltinModule("child_process").onRequire((exports, pkgInfo) => { (0, wrapExport_1.wrapExport)(exports, "execSync", pkgInfo, { kind: "exec_op", inspectArgs: (args) => { return this.inspectExec(args, "execSync"); }, }); (0, wrapExport_1.wrapExport)(exports, "spawn", pkgInfo, { kind: "exec_op", inspectArgs: (args) => { return this.inspectSpawn(args, "spawn"); }, }); (0, wrapExport_1.wrapExport)(exports, "spawnSync", pkgInfo, { kind: "exec_op", inspectArgs: (args) => { return this.inspectSpawn(args, "spawnSync"); }, }); (0, wrapExport_1.wrapExport)(exports, "execFile", pkgInfo, { // Also protects exec, see https://github.com/nodejs/node/blob/main/lib/child_process.js kind: "exec_op", inspectArgs: (args) => { return this.inspectExecFile(args, "execFile"); }, }); (0, wrapExport_1.wrapExport)(exports, "execFileSync", pkgInfo, { kind: "exec_op", inspectArgs: (args) => { return this.inspectExecFile(args, "execFileSync"); }, }); (0, wrapExport_1.wrapExport)(exports, "fork", pkgInfo, { kind: "exec_op", inspectArgs: (args) => { return this.inspectFork(args, "fork"); }, }); }); } inspectFork(args, name) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (args.length > 0 && typeof args[0] === "string") { const modulePath = args[0]; return (0, checkContextForPathTraversal_1.checkContextForPathTraversal)({ filename: modulePath, operation: `child_process.${name}`, context: context, }); } return undefined; } inspectSpawn(args, name) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (!this.usingShell(args)) { return undefined; } if (args.length > 0 && typeof args[0] === "string") { let command = args[0]; if (args.length > 1 && Array.isArray(args[1]) && args[1].length > 0) { command = `${command} ${args[1].join(" ")}`; } return (0, checkContextForShellInjection_1.checkContextForShellInjection)({ command: command, operation: `child_process.${name}`, context: context, }); } } inspectExecFile(args, name) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (!this.usingShell(args)) { return undefined; } if (args.length > 0 && typeof args[0] === "string") { let command = args[0]; if (args.length > 1 && Array.isArray(args[1]) && args[1].length > 0) { command = `${command} ${args[1].join(" ")}`; } return (0, checkContextForShellInjection_1.checkContextForShellInjection)({ command: command, operation: `child_process.${name}`, context: context, }); } } inspectExec(args, name) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (args.length > 0 && typeof args[0] === "string") { const command = args[0]; return (0, checkContextForShellInjection_1.checkContextForShellInjection)({ command: command, operation: `child_process.${name}`, context: context, }); } return undefined; } isShellCommand(command) { for (const prefix of PATH_PREFIXES) { for (const shellCommand of ["bash", "zsh", "sh"]) { if (command === `${prefix}${shellCommand}` || command === shellCommand) { return true; } } } return false; } usingShell(args) { if (args.length > 0 && typeof args[0] === "string" && this.isShellCommand(args[0])) { return true; } return args.some((arg) => (0, isPlainObject_1.isPlainObject)(arg) && "shell" in arg && (arg.shell === true || typeof arg.shell === "string")); } } exports.ChildProcess = ChildProcess;