Null Byte in File Paths (Legacy PHP)
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5), semgrep rules for include/$_GET patterns will flag this, but it's silent at runtime on vulnerable PHP versions.
Closest to 'simple parameterised fix' (e3), quick_fix is sanitise with str_replace(chr(0), '', $input) plus realpath check, or upgrade PHP — small targeted change per include site.
Closest to 'localised tax' (b3), affects file inclusion code paths in legacy web apps; applies_to is narrow (PHP 3.0-5.3 web contexts) so reach is bounded.
Closest to 'serious trap' (t7), misconception is that modern PHP fixed it everywhere — extension append validation looks safe but null byte truncates the path, contradicting normal string handling intuition.
TL;DR
Explanation
In PHP < 5.3.4, a null byte in a string terminated C-level string functions. Attackers exploited this: include $_GET['file'] . '.php'; with file=../../../../etc/passwd%00 stripped the .php extension, including /etc/passwd. Fixed in PHP 5.3.4 — file functions now reject strings containing NUL. PHP 7 throws ValueError for NUL in filenames. Legacy codebases on older PHP: validate with strpos($input, chr(0)) !== false. Modern PHP (7+): not exploitable but still worth sanitising for defence in depth.
Common Misconception
Why It Matters
Common Mistakes
- Not upgrading from PHP 5.3.3 or earlier on legacy systems.
- Not sanitising null bytes in input even on modern PHP (defence in depth).
- Relying solely on extension append (.php) for security — null byte bypassed this.
Code Examples
// PHP < 5.3.4 — vulnerable:
$file = $_GET['file']; // 'shell.php%00'
include $file . '.php'; // Includes shell.php, ignores .php suffix
// Modern PHP (7+) throws automatically
// Defence in depth — sanitise anyway:
$file = str_replace(chr(0), '', $_GET['file'] ?? '');
$file = basename($file); // Remove path traversal
$path = realpath('/uploads/' . $file);
if ($path === false || !str_starts_with($path, '/uploads/')) {
abort(400);
}