Path Traversal
Learn how to prevent directory traversal attacks with examples, cheat sheets, and best practices. Protect your web server from path traversal vulnerabilities and security threats.
Tools recognizing this:
Opengrep Fortify Checkmarx SonarQube Snyk Semgrep CodeQL
What is Directory Traversal
Directory Traversal (also known as Path Traversal or Path Manipulation) is a common web security vulnerability that allows attackers to access restricted directories and execute unauthorized commands. This guide covers directory traversal attacks, examples, prevention methods, and how to fix path traversal vulnerabilities in different programming languages.
The vulnerability occurs when an application accepts user input to construct file paths without proper validation or sanitization.
The user input can potentially include malicious sequences that manipulate the file path to allow attacker unauthorized actions:
Access files outside the intended directory
Read sensitive system files
Modify or delete critical files
Execute malicious files
Potentially gain access to the entire file system
One Simple Example
Consider this classic example of file access:
String filePath = baseDir + "/" + userInput;
File file = new File(filePath);An attacker could provide this input:
../../../etc/passwd
The resulting path becomes:
/var/www/app/../../../etc/passwd
This allows the attacker to access the system's password file located at /etc/passwd, which is outside the intended directory structure.
Real-world Occurrences of Path Traversal
Zoom Path Traversal Vulnerability (2020)
In 2020, Zoom had a critical path traversal vulnerability in their messaging feature, that could allow attackers to execute arbitrary code on other meeting attendees' machines.
Impact: Potential remote code execution on users' systems.
Apache HTTP Server Path Traversal (2021)
A severe path traversal vulnerability in Apache HTTP Server 2.4.49 allowed attackers to map URLs to files outside the expected document root.
Impact: Remote attackers could access files outside of the web root directory, potentially exposing sensitive information and in some case remote code execution. This issue is known to be exploited in the wild.
Fixing Path Traversal
The most efficient way to fix a Path Traversal issue in your code is using proper input validation and path canonicalization.
Path canonicalization ensures that file paths are converted to their simplest form, removing any relative path components. Input validation ensures that user-provided paths only contain allowed characters and patterns, preventing directory traversal attempts.
Code Samples
Vulnerable Code
String userInput = request.getParameter("fileName");
File file = new File(baseDir + "/" + userInput);
FileInputStream fis = new FileInputStream(file);Fixed Code
String userInput = request.getParameter("fileName");
File file = new File(baseDir, userInput).getCanonicalFile();
if (!file.getCanonicalPath().startsWith(new File(baseDir).getCanonicalPath())) {
throw new SecurityException("Invalid file path");
}
FileInputStream fis = new FileInputStream(file);Fix Explanation
The vulnerable code directly concatenates user input into the file path. The fix uses getCanonicalFile() to resolve the actual path. Validates that the resolved path is within the intended base directory. Throws a security exception if path traversal is attempted.
Vulnerable Code
const filePath = path.join(baseDir, userInput);
fs.readFileSync(filePath);Fixed Code
const safePath = path.normalize(userInput).replace(/^(\.\.(\/|\\|$))+/, '');
const filePath = path.join(baseDir, safePath);
if (!filePath.startsWith(baseDir)) {
throw new Error('Invalid file path');
}
fs.readFileSync(filePath);Fix Explanation
The vulnerable code directly joins user input with the base directory. The fix normalizes the path and removes any directory traversal sequences. Validates that the final path stays within the base directory. Throws an error if path traversal is attempted.
Vulnerable Code
file_path = os.path.join(base_dir, user_input)
with open(file_path, 'r') as file:
content = file.read()Fixed Code
safe_path = os.path.normpath(user_input)
if safe_path.startswith('..'):
raise ValueError("Invalid file path")
file_path = os.path.join(base_dir, safe_path)
if not os.path.commonpath([file_path, base_dir]) == base_dir:
raise ValueError("Invalid file path")
with open(file_path, 'r') as file:
content = file.read()Fix Explanation
The vulnerable code directly joins paths without validation. The fix normalizes the path and checks for traversal attempts. Uses commonpath to ensure the path stays within base directory. Raises an error if path traversal is detected.
Vulnerable Code
string filePath = Path.Combine(baseDir, userInput);
string content = File.ReadAllText(filePath);Fixed Code
string safePath = Path.GetFullPath(Path.Combine(baseDir, userInput));
if (!safePath.StartsWith(Path.GetFullPath(baseDir), StringComparison.OrdinalIgnoreCase))
{
throw new SecurityException("Invalid file path");
}
string content = File.ReadAllText(safePath);Fix Explanation
The vulnerable code combines paths without validation. The fix uses GetFullPath to resolve the actual path. Validates that the path stays within the base directory. Uses case-insensitive comparison for Windows compatibility.
Vulnerable Code
$file_path = $base_dir . '/' . $_GET['file'];
$content = file_get_contents($file_path);Fixed Code
$user_input = basename($_GET['file']);
$file_path = realpath($base_dir . '/' . $user_input);
if ($file_path === false || !str_starts_with($file_path, realpath($base_dir))) {
throw new Exception('Invalid file path');
}
$content = file_get_contents($file_path);Fix Explanation
The vulnerable code directly concatenates user input. The fix uses basename to remove directory components. Uses realpath to resolve the actual path. Validates that the path stays within base directory.
Vulnerable Code
string filePath = baseDir + "/" + userInput;
ifstream file(filePath);
string content((istreambuf_iterator<char>(file)), {});Fixed Code
filesystem::path safePath = filesystem::absolute(baseDir / userInput);
if (!filesystem::equivalent(safePath.parent_path(), baseDir)) {
throw runtime_error("Invalid file path");
}
ifstream file(safePath);
string content((istreambuf_iterator<char>(file)), {});Fix Explanation
The vulnerable code directly concatenates paths. The fix uses filesystem::path for safe path handling. Validates that the parent path matches the base directory. Throws an error if path traversal is detected.
Last updated
Was this helpful?