@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
JavaScript
;
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;