Skip to content

Back to the catalog

bencteux.frwriteup

PHP's open_basedir is not a security feature

The author dissects PHP's open_basedir directive by reading php-src's php_check_open_basedir enforcement code, and finds two functions — bindtextdomain() and opcache_invalidate() — that fail to call the guard, allowing an attacker to use them as file-existence oracles outside the restricted directory tree (tested on PHP 8.0.7, reported to maintainers 2021-07-12). It also documents PHP maintainers' longstanding position that "open_basedir bypasses are no security issues," and notes the PHP manual was subsequently updated to caution that open_basedir is only an extra safety net and must not be relied upon for security.

TL;DR Source-review of PHP's open_basedir finds bindtextdomain() and opcache_invalidate() skip the enforcement check, turning them into file-existence oracles — reinforcing that open_basedir was never meant as a real security boundary.
Document

What it is

A technical writeup demonstrating that PHP's open_basedir directive is not enforced uniformly across the standard library. The author read php_check_open_basedir() in php-src/main/fopen_wrappers.c and identified two functions — bindtextdomain() (in ext/gettext/gettext.c) and opcache_invalidate() — whose path arguments skip the guard entirely, giving a file-existence oracle for paths outside the restricted tree. Testing was done on PHP 8.0.7.

How it works

Most path-taking functions call php_check_open_basedir(path), which loops over the configured basedirs and delegates per-path checks to php_check_specific_open_basedir(), returning -1 and emitting the familiar warning when the path escapes. Any function that omits this call can touch files outside the hierarchy. The two identified functions leak existence rather than contents:

  • bindtextdomain("test", "../test.txt") returns the resolved absolute path (e.g. /var/www/html/test.txt) if the file exists, instead of the open_basedir warning.
  • opcache_invalidate("../test.txt") returns 1 on an existing out-of-tree file instead of failing.

Preconditions / Affected

Attacker must already be able to run PHP (e.g. via an upload or code-injection foothold) in an environment relying on open_basedir as a boundary. The demonstrated bypasses grant only file-existence probing outside the restricted path, not read/write — though the author notes others have published bypasses that do read or write files.

What to do

Do not treat open_basedir as a security boundary. The concrete, load-bearing fact here is the PHP maintainers' stated position: they consider "open_basedir bypasses are no security issues" and have questioned whether the feature should exist at all — so these gaps will not be triaged or patched as vulnerabilities. Both functions were reported (bindtextdomain on 2021-07-12; opcache_invalidate also reported), and the maintainers reportedly amended the documentation rather than fix the code. Isolate untrusted PHP with real controls (containers, filesystem permissions, seccomp) instead.

Caveats

The author explicitly warns the specific PoCs were tested on PHP 8.0.7 and "it is likely that it will not work anymore" — treat the two named functions as illustrative of the pattern, not a current exploit list. The bypass is partial: it yields a file-existence oracle only, not arbitrary read/write.

Organisations named here

  • bindtextdomain
  • opcache_invalidate
  • php_check_open_basedir

Technologies named here

  • PHP

Techniques named here

  • open_basedir bypass via bindtextdomain
  • open_basedir bypass via opcache_invalidate