UNPKG

@aikidosec/firewall

Version:

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

134 lines (133 loc) 6.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FileSystem = void 0; const Context_1 = require("../agent/Context"); const wrapExport_1 = require("../agent/hooks/wrapExport"); const getNodeVersion_1 = require("../helpers/getNodeVersion"); const isVersionGreaterOrEqual_1 = require("../helpers/isVersionGreaterOrEqual"); const checkContextForPathTraversal_1 = require("../vulnerabilities/path-traversal/checkContextForPathTraversal"); class FileSystem { constructor() { this.patchedPromises = false; } inspectPath(args, name, amountOfPathArgs) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } for (const path of args.slice(0, amountOfPathArgs)) { if (typeof path === "string" || path instanceof Buffer || path instanceof URL) { const result = (0, checkContextForPathTraversal_1.checkContextForPathTraversal)({ filename: path, operation: `fs.${name}`, context: context, }); if (result) { return result; } } } return undefined; } getFunctions() { const functions = { appendFile: { pathsArgs: 1, sync: true, promise: true }, chmod: { pathsArgs: 1, sync: true, promise: true }, chown: { pathsArgs: 1, sync: true, promise: true }, createReadStream: { pathsArgs: 1, sync: false, promise: false }, createWriteStream: { pathsArgs: 1, sync: false, promise: false }, lchown: { pathsArgs: 1, sync: true, promise: true }, lutimes: { pathsArgs: 1, sync: true, promise: true }, mkdir: { pathsArgs: 1, sync: true, promise: true }, open: { pathsArgs: 1, sync: true, promise: true }, opendir: { pathsArgs: 1, sync: true, promise: true }, readdir: { pathsArgs: 1, sync: true, promise: true }, readFile: { pathsArgs: 1, sync: true, promise: true }, readlink: { pathsArgs: 1, sync: true, promise: true }, unlink: { pathsArgs: 1, sync: true, promise: true }, realpath: { pathsArgs: 1, sync: true, promise: true }, rename: { pathsArgs: 2, sync: true, promise: true }, rmdir: { pathsArgs: 1, sync: true, promise: true }, rm: { pathsArgs: 1, sync: true, promise: true }, symlink: { pathsArgs: 2, sync: true, promise: true }, truncate: { pathsArgs: 1, sync: true, promise: true }, utimes: { pathsArgs: 1, sync: true, promise: true }, writeFile: { pathsArgs: 1, sync: true, promise: true }, copyFile: { pathsArgs: 2, sync: true, promise: true }, cp: { pathsArgs: 2, sync: true, promise: true }, link: { pathsArgs: 2, sync: true, promise: true }, watch: { pathsArgs: 1, sync: false, promise: false }, watchFile: { pathsArgs: 1, sync: false, promise: false }, mkdtemp: { pathsArgs: 1, sync: true, promise: true }, }; // Added in v19.8.0 if ((0, isVersionGreaterOrEqual_1.isVersionGreaterOrEqual)("19.8.0", (0, getNodeVersion_1.getSemverNodeVersion)())) { functions.openAsBlob = { pathsArgs: 1, sync: false, promise: false }; } // Only available on macOS if (process.platform === "darwin") { functions.lchmod = { pathsArgs: 1, sync: true, promise: true }; } return functions; } wrapPromises(exports, pkgInfo) { if (this.patchedPromises) { // `require("fs").promises.readFile` is the same as `require("fs/promises").readFile` // We only need to wrap the promise version once return; } const functions = this.getFunctions(); Object.keys(functions).forEach((name) => { const { pathsArgs, promise } = functions[name]; if (promise) { (0, wrapExport_1.wrapExport)(exports, name, pkgInfo, { kind: "fs_op", inspectArgs: (args) => this.inspectPath(args, name, pathsArgs), }); } }); this.patchedPromises = true; } wrap(hooks) { hooks.addBuiltinModule("fs").onRequire((exports, pkgInfo) => { const functions = this.getFunctions(); Object.keys(functions).forEach((name) => { const { pathsArgs, sync } = functions[name]; (0, wrapExport_1.wrapExport)(exports, name, pkgInfo, { kind: "fs_op", inspectArgs: (args) => { return this.inspectPath(args, name, pathsArgs); }, }); if (sync) { (0, wrapExport_1.wrapExport)(exports, `${name}Sync`, pkgInfo, { kind: "fs_op", inspectArgs: (args) => { return this.inspectPath(args, `${name}Sync`, pathsArgs); }, }); } }); // Wrap realpath.native (0, wrapExport_1.wrapExport)(exports.realpath, "native", pkgInfo, { kind: "fs_op", inspectArgs: (args) => { return this.inspectPath(args, "realpath.native", 1); }, }); (0, wrapExport_1.wrapExport)(exports.realpathSync, "native", pkgInfo, { kind: "fs_op", inspectArgs: (args) => { return this.inspectPath(args, "realpathSync.native", 1); }, }); this.wrapPromises(exports.promises, pkgInfo); }); hooks .addBuiltinModule("fs/promises") .onRequire((exports, pkgInfo) => this.wrapPromises(exports, pkgInfo)); } } exports.FileSystem = FileSystem;