UNPKG

@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.

78 lines (77 loc) 3.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.detectPathTraversal = detectPathTraversal; const containsUnsafePathParts_1 = require("./containsUnsafePathParts"); const unsafePathStart_1 = require("./unsafePathStart"); const url_1 = require("url"); function detectPathTraversal(filePath, userInput, checkPathStart = true, isUrl = false) { if (userInput.length <= 1) { // We ignore single characters since they don't pose a big threat. return false; } // Check for URL path traversal // Reason: new URL("file:///../../test.txt") => /test.txt // The normal check for relative path traversal will fail in this case, because transformed path does not contain ../. // For absolute path traversal, we dont need to check the transformed path, because it will always start with /. // Also /./ is checked by normal absolute path traversal check (if #219 is merged) // Use containsUnsafePathPartsUrl, because urls can contain a TAB, carriage return or line feed that is silently removed by the URL constructor. if (isUrl && (0, containsUnsafePathParts_1.containsUnsafePathPartsUrl)(userInput)) { const filePathFromUrl = parseAsFileUrl(userInput); if (filePathFromUrl && filePath.includes(filePathFromUrl)) { return true; } } if (userInput.length > filePath.length) { // We ignore cases where the user input is longer than the file path. // Because the user input can't be part of the file path. return false; } if (!filePath.includes(userInput)) { // We ignore cases where the user input is not part of the file path. return false; } if ((0, containsUnsafePathParts_1.containsUnsafePathParts)(filePath) && (0, containsUnsafePathParts_1.containsUnsafePathParts)(userInput)) { return true; } if (checkPathStart) { // Check for absolute path traversal return (0, unsafePathStart_1.startsWithUnsafePath)(filePath, userInput); } return false; } /** * This function is used to convert a file path as a URL to a file path. * It is used to handle cases where a URL object is passed to a fs function. * For example new URL("file:///../../test.txt") => file:///test.txt * This function will convert ../../test.txt to /test.txt * If the URL is not a file URL, it will return undefined. * Another sample: new URL("file:///./test.txt") => /test.txt */ function parseAsFileUrl(path) { let url = path; if (!isFileUrlString(url)) { if (!url.startsWith("/")) { url = `/${url}`; } url = `file://${url}`; } try { return (0, url_1.fileURLToPath)(url); } catch { // } return undefined; } /** * Checks if a string starts with "file:" to determine if it is a file URL. * Removes control characters and spaces at the start of the path and checks lowercase. * See https://url.spec.whatwg.org/#url-parsing */ function isFileUrlString(path) { return (path // oxlint-disable-next-line no-control-regex .replace(/^[\u0000-\u0020]+/, "") .toLowerCase() .startsWith("file:")); }