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

realpath()

PHP PHP 5.0+ Intermediate
debt(d7/e3/b3/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). Semgrep/Psalm rules can flag file operations without realpath() but the subtle bug (missing base-dir prefix check, unchecked false return) typically requires code review to catch reliably.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). Per quick_fix, the remediation is adding realpath() plus a str_starts_with() base-dir check at each file-access site — a pattern replacement, not a one-liner, since false-return handling must also be added.

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

Closest to 'localised tax' (b3). Applies to file-handling code paths only; doesn't shape the whole system but creates a recurring check pattern wherever user paths touch the filesystem.

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

Closest to 'serious trap' (t7). The misconception is exactly that realpath() alone sanitises paths — it doesn't; it also returns false for non-existent paths which silently breaks naive comparisons. Contradicts the intuitive 'canonical = safe' mental model.

About DEBT scoring →

Also Known As

realpath() PHP canonical path resolve symlinks

TL;DR

Resolves a path to its canonical absolute form, collapsing ../ sequences — used to prevent path traversal.

Explanation

realpath($path) resolves all symbolic links, /../ and /./ sequences, and redundant separators to produce the canonical absolute path. It returns false if the file doesn't exist. The standard path traversal guard is: $real = realpath($base . '/' . $userInput); if ($real === false || strpos($real, $base) !== 0) { deny; }. This ensures the resolved path starts with the intended base directory, regardless of what the user submitted.

Common Misconception

realpath() is safe to use on any user-supplied path. realpath() resolves the canonical path including symlinks — it returns false for non-existent paths, which must be checked. Always verify the resolved path starts with the expected base directory before using it.

Why It Matters

realpath() resolves symlinks, . and .. components, and returns the canonical absolute path — it is the essential step before comparing user-supplied paths to allowed base directories.

Common Mistakes

  • Checking path prefix before calling realpath() — traversal sequences pass the check but resolve differently.
  • Not handling realpath() returning false for non-existent paths — the comparison silently fails.
  • Using realpath() without checking that the result starts with the intended base directory.
  • Trusting that realpath() sanitises the path for security without the subsequent base-directory check.

Code Examples

✗ Vulnerable
// Check before realpath — bypassable:
$path = '/var/www/uploads/' . $_GET['file'];
if (str_starts_with($path, '/var/www/uploads/')) {
    readfile($path); // ../../etc/passwd passes the check!
}

// Correct:
$real = realpath('/var/www/uploads/' . $_GET['file']);
if ($real === false || !str_starts_with($real, '/var/www/uploads/')) die('Denied');
readfile($real);
✓ Fixed
// realpath() resolves ../, ./, symlinks to canonical absolute path
// Returns false if path doesn't exist
$base = realpath('/var/www/uploads');
$path = realpath($base . '/' . $_GET['file']);

if ($path === false) abort(404);  // file doesn't exist
if (!str_starts_with($path, $base . DIRECTORY_SEPARATOR)) abort(403); // path traversal

readfile($path);

// basename() strips directory components:
basename('../../../etc/passwd'); // 'passwd'
$safe = '/var/www/uploads/' . basename($_GET['file']); // still need realpath() too

Added 15 Mar 2026
Edited 22 Mar 2026
Views 52
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 2 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 2 pings F 2 pings S 1 ping S 1 ping M 3 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 8 Ahrefs 7 Scrapy 6 Perplexity 5 SEMrush 5 Unknown AI 3 Google 3 Claude 2 ChatGPT 2 Bing 2 Meta AI 1 Sogou 1 PetalBot 1
crawler 41 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Always use realpath() to resolve the canonical absolute path before file operations on user-supplied paths — then verify the resolved path starts with your allowed base directory with str_starts_with()
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
File operations with user-supplied path without realpath() validation; path traversal ../ not checked; file existence checked by different path than used
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✓ Auto-fixable Fix: Low Context: Function
CWE-22 CWE-73


✓ schema.org compliant