~ 3 min read
Secure Coding Practices in Node.js Against Path Traversal Vulnerabilities
Path traversal vulnerabilities can grant attackers unauthorized access to your file system, potentially leading to data exfiltration, code execution, or server compromise.
In this article I want to mention secure coding practices to prevent these vulnerabilities and analyze real-world examples (CVE-2024-29180, CVE-2024-26150) to illustrate the impact and mitigation strategies.
Real-World Examples of Path Traversal Vulnerabilities
1. CVE-2024-29180: webpack-dev-middleware
This vulnerability resides in the webpack-dev-middleware
package. Due to insufficient validation of user-supplied URLs, an attacker can exploit path traversal to access arbitrary files on the developer’s machine.
The following versions of webpack-dev-middleware
are affected: version < 5.3.4, >= 6.0.0 < 6.1.2, >= 7.0.0 < 7.1.0
The impact is potential exfiltration of sensitive data (source code, configuration files), and server compromise if critical system files are accessed.
Here’s a Proof-of-Concept (POC) demonstrating the vulnerability:
// Vulnerable webpack configuration (writeToDisk: true)
module.exports = {
devServer: {
devMiddleware: {
writeToDisk: true,
},
},
};
// Malicious request to access /etc/passwd
curl localhost:8080/public/..%2f..%2f..%2f..%2f../etc/passwd
The vulnerable code snippet from the webpack-dev-middleware
package:
// (webpack-dev-middleware source code)
getFilenameFromUrl(url) {
const publicPath = ...; // Public path configuration
const filePath = url.replace(publicPath, '');
return path.join(outputPath, filePath);
}
The fix is to upgrade to webpack-dev-middleware
version 5.3.4 or later, which addresses this vulnerability.
2. CVE-2024-26150: @backstage/backend-common
This vulnerability affects the @backstage/backend-common package. Flawed symlink checks in the resolveSafeChildPath function allow path traversal attacks.
The backstage/backend-common
affected version range is: < 0.19.10, >= 0.20.0-next.0 < 0.20.2, >= 0.21.0-next.0 < 0.21.1.
The impact on vulnerable backstage package verssions is unauthorized access to files outside the intended directory.
The following is the vulnerable code snippet from the @backstage/backend-common
package:
const targetPath = resolvePath(base, path);
if (!isChildPath(resolveRealPath(base), resolveRealPath(targetPath))) {
throw new NotAllowedError(
'Relative path is not allowed to refer to a directory outside its parent',
);
}
Here too, the fix is to upgrade to @backstage/backend-common
version 0.19.10 or later, which includes a fix for this vulnerability.
JavaScript Secure Coding Principles
By adhering to secure coding practices and staying updated on vulnerable package versions, you can significantly reduce the risk of path traversal vulnerabilities in your Node.js applications.
Remember, a layered defense approach that combines secure coding, regular dependency updates, and vulnerability scanning is crucial for maintaining a secure development environment.
Consider the following secure coding principles to protect your Node.js applications against path traversal vulnerabilities:
Avoid User-Supplied Path Concatenation: Never directly concatenate user-supplied paths to existing paths before passing them to
path.join
orpath.resolve
. This allows attackers to inject malicious path manipulations using sequences like../
.Sanitization is Not Enough:
path.normalize
is not a standalone security solution. It may remove some redundant path elements but doesn’t prevent traversal attacks. Sanitizing specific characters like..
is also ineffective as attackers can use URL encoding techniques to bypass such filters.Decode User Input Before Resolution: Apply URL decoding functions like
decodeURI
anddecodeURIComponent
on user-supplied paths before resolving them. This helps mitigate attempts to exploit encoded path traversal characters.