flawopen.com/Path Traversal/PHP
PHP is told to load 'page.php'. An attacker passes '../../../../etc/passwd', and PHP obligingly dumps the system password file right onto the webpage.
In PHP, include($base . '/' . $_GET['page']) or readfile() allows attackers to pass ../ tokens or PHP stream wrappers (php://filter) to read arbitrary files.
Path traversal and Local File Inclusion (LFI) in PHP have historically accounted for thousands of Remote Code Execution bugs, including landmark CMS vulnerabilities.
CISA Cybersecurity Advisory & MITRE CVE repository.<?php // VULNERABLE: Direct concatenation in file read $base_dir = '/var/www/uploads'; $file = $_GET['file']; // Attacker input: ../../../../etc/passwd $path = $base_dir . '/' . $file; // Dumps arbitrary server file to user readfile($path); ?>
<?php
// HARDENED: Canonicalize with realpath and enforce directory prefix check
$base_dir = realpath('/var/www/uploads');
$file = $_GET['file'] ?? '';
if (!is_string($file) || empty($file)) {
http_response_code(400);
exit('Invalid file parameter');
}
// 1. Resolve canonical path
$real_target = realpath($base_dir . DIRECTORY_SEPARATOR . $file);
// 2. Strict boundary check (ensure prefix matches base_dir + separator)
$expected_prefix = $base_dir . DIRECTORY_SEPARATOR;
if ($real_target === false || !str_starts_with($real_target, $expected_prefix)) {
http_response_code(403);
exit('Forbidden: Path Traversal detected');
}
if (!is_file($real_target)) {
http_response_code(404);
exit('File not found');
}
readfile($real_target);
?>
realpath() resolves all traversal tokens. Checking str_starts_with($real_target, $base_dir . DIRECTORY_SEPARATOR) guarantees the resolved file sits strictly within the intended uploads directory.
If realpath() returns false, the file does not exist or permissions prevent resolution. Always check for false before checking str_starts_with.
basename() strips directory paths, but also prevents users from accessing legitimate subfolders within an allowed directory tree.
psalm --taint-analysis
phpstan analyse
realpath() to resolve absolute pathsstr_starts_with($target, $base . DIRECTORY_SEPARATOR)is_file($target) before calling readfile() or includeNo. PHP 8.0+ has fully eliminated null byte (\0) truncation bugs in filesystem functions.