@aikidosec/firewall
Version:
Zen by Aikido is an embedded Application Firewall that autonomously protects Node.js apps against common and critical attacks, provides rate limiting, detects malicious traffic (including bots), and more.
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;
;