open_basedir Restriction
debt(d5/e1/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list lynis, phpinfo, and semgrep — these are specialist security/SAST tools rather than default linters or compilers. A missing or misconfigured open_basedir won't surface as a compile or lint error; it requires running a server auditor (lynis) or SAST scanner (semgrep), or manually inspecting phpinfo() output.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix is explicit: add 'open_basedir=/var/www/html:/tmp' to php.ini — a single configuration line. No code refactor is needed; it's a pure ini-level change.
Closest to 'localised tax' (b3). The applies_to scope is web contexts only, and open_basedir is a php.ini/server configuration concern. It imposes a modest ongoing tax — developers must remember path allowances when adding new upload directories, session paths, or tmp usage — but it doesn't reshape the broader codebase or affect non-web contexts.
Closest to 'serious trap' (t7). The misconception field states directly that open_basedir is treated as a reliable security boundary, when in fact it is bypassable via certain PHP extensions, symlinks, and glob() patterns. This contradicts the intuition developers bring from OS-level chroot or filesystem ACLs. Additional traps in common_mistakes include setting it to '/' (disabling it silently), inadvertently including /tmp as an escape vector, and .htaccess overrides silently voiding the restriction — all of which a competent developer would likely get wrong without specific PHP knowledge.
Also Known As
TL;DR
Explanation
open_basedir limits PHP's file functions (fopen, file_get_contents, include, require, etc.) to files within the specified path prefix. An attacker who achieves LFI or path traversal is then confined to the permitted directory and cannot read /etc/passwd or other sensitive files outside the web root. Set it to the application directory and any required upload/temp paths: open_basedir = /var/www/html:/tmp. Note that open_basedir is a defence-in-depth measure — it does not replace input validation, and some bypass techniques exist on misconfigured servers.
Common Misconception
Why It Matters
Common Mistakes
- Not configuring open_basedir in production — a path traversal vulnerability can then read any world-readable file.
- Setting open_basedir to / (root) which is equivalent to disabling it.
- Including /tmp in open_basedir without realising session files, uploads, and shell upload targets may be in /tmp.
- Not testing that open_basedir restrictions survive php.ini overrides in user .htaccess files.
Code Examples
# php.ini — open_basedir not configured:
; open_basedir = (commented out — no restriction)
; Attacker can read: include '../../../../etc/passwd';
; php.ini — restrict PHP filesystem access to specified paths
open_basedir = /var/www/app:/tmp
; PHP raises an error if it tries to access files outside these dirs
; Mitigates path traversal and LFI impact significantly
; Per virtual host (overrides global):
; fastcgi_param PHP_VALUE "open_basedir=/var/www/site1:/tmp";
; PHP code — detect if restriction is active:
if (ini_get('open_basedir')) {
// Filesystem is restricted
}
; Note: not a security boundary for determined attackers with code execution
; but raises the bar significantly for exploitation
; Combine with: chroot jails, seccomp, read-only mounts