← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Null Byte Injection

Security CWE-626 OWASP A3:2021 CVSS 7.5 PHP 5.0+ Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list Semgrep as the tool, with automated detection possible for PHP <5.3.4 with user-controlled file paths and C extension patterns. This is not a default linter catch (d3) but requires a configured SAST tool like Semgrep. The residual risk in modern PHP (C extensions, regex, string comparisons) makes it harder than a simple pattern match, keeping it at d5.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix indicates: in modern PHP (5.3.4+) the file-path case is handled automatically; for C extension interactions, a single str_contains($input, "\0") check rejects null bytes. The common_mistakes show the fix is primarily adding a null byte stripping/rejection step to input handling — a small, localised change. Not quite a one-liner across all surfaces (multiple entry points may need patching), but no cross-cutting architectural rework required.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to scope is web and cli contexts but is primarily a legacy issue (php_max 5.3.3 for the file-function variant). Modern codebases interacting with C extensions carry a persistent but narrow validation responsibility — it's a localised input-sanitisation tax on specific code paths (file uploads, path construction, C extension calls) rather than a systemic architectural burden.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states developers believe this is a legacy PHP 5 issue that no longer applies, when in fact null bytes still affect regex matching, string comparisons, and C-based library calls in modern PHP. This directly contradicts the common mental model — the 'obvious' conclusion (upgrade past 5.3.4 and you're safe) is wrong in a non-trivial set of cases, making it a serious trap that contradicts expectations set by the PHP fix itself.

About DEBT scoring →

Also Known As

null byte attack %00 injection NUL byte bypass

TL;DR

Inserting a %00 null byte into a filename or string can truncate it at the C layer, bypassing extension checks.

Explanation

Null byte injection exploits the difference between PHP string handling and underlying C library functions. PHP strings can contain null bytes, but C functions treat null as a string terminator. Injecting %00 into a filename like shell.php%00.jpg causes PHP's extension check to see .jpg while the file system writes shell.php. This was patched in PHP 5.3.4 for filesystem functions, but can still affect custom validation logic or older systems. Always use pathinfo() for extension extraction rather than string manipulation.

How It's Exploited

GET /read?file=../../etc/passwd%00
# Null byte truncates the appended .txt, reads /etc/passwd on old PHP

Common Misconception

Null byte injection is a legacy PHP 5 issue that no longer applies. While PHP fixed it in file functions, null bytes still affect regex matching, string comparisons, and any code passing data to C-based libraries that treat NUL as a string terminator.

Why It Matters

A null byte (%00) terminates strings in C-based PHP extensions — a filename like shell.php%00.jpg was processed as shell.php by older PHP file functions, enabling upload bypass.

Common Mistakes

  • Relying solely on extension whitelisting without also stripping null bytes from filenames.
  • Using old PHP (pre-5.3.4) where null bytes in filenames caused file function truncation.
  • Not applying null byte stripping when constructing file paths from user input even in modern PHP where some extensions may still be vulnerable.
  • Ignoring null bytes in database queries that use native C extensions.

Code Examples

✗ Vulnerable
// Null byte terminates filename in PHP < 5.3.4
$file = $_GET['file'] . '.txt';
readfile('/data/' . $file);
// ?file=secret.php%00 → reads 'secret.php' (ignores '.txt')
✓ Fixed
// Modern PHP raises ValueError on null bytes in filesystem calls
// Still sanitise defensively:
$file = str_replace("\0", '', $_GET['file'] ?? '');

// Best: realpath + prefix check
$base = realpath('/data');
$path = realpath($base . '/' . $file . '.txt');
if (!$path || !str_starts_with($path, $base . DIRECTORY_SEPARATOR)) abort(403);
readfile($path);

Added 15 Mar 2026
Edited 12 Jun 2026
Views 112
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping W 1 ping T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 1 ping S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 2 pings T 1 ping W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
PetalBot 14 Amazonbot 13 Ahrefs 8 SEMrush 8 ChatGPT 5 Perplexity 3 Google 3 Brave Search 3 Unknown AI 2 Bing 2 Scrapy 2 Majestic 2 Applebot 2 Meta AI 1 Twitter/X 1
crawler 64 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
In modern PHP (5.3.4+) null bytes in file paths throw an error automatically; for any C extension interaction, use str_contains($input, "\0") to explicitly reject null bytes
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
PHP <5.3.4 with user-controlled file paths; C extension receiving user input without null byte check
Auto-detectable: ✓ Yes semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line
CWE-626 CWE-158


✓ schema.org compliant