flawopen.com/File Inclusion/PHP include()
Is PHP's include() safe with user input?
No. include parses the selected file as PHP, but impact depends on what can be reached and what that file contains. A path flaw may disclose source through a wrapper, include an unintended local file, or execute attacker-controlled PHP only when the attacker can influence PHP-tagged content and the application includes it. Remote URL inclusion additionally depends on PHP configuration. Map a user-selected key to a fixed allowlist; never build an include path from request data.
<?php // User-controlled path: unintended local file include $_GET['page'] . '.php'; // Example selector: ../../private/sample // Impact depends on the resolved file and // whether it contains PHP code to interpret. // Remote URL inclusion requires the relevant // URL wrapper and allow_url_include setting. // Wrappers can change which resource is read; // php://filter is a read filter, not a path // containment check.
<?php // Allowlist: input selects a KEY, // never a path or wrapper. $pages = [ 'home' => __DIR__ . '/pages/home.php', 'about' => __DIR__ . '/pages/about.php', 'contact' => __DIR__ . '/pages/contact.php', ]; $key = $_GET['page'] ?? 'home'; if (!is_string($key) || !array_key_exists($key, $pages)) { http_response_code(404); exit; } include $pages[$key];
Why local inclusion is not the "mild" version
Local file inclusion is not automatically code execution. PHP switches into PHP parsing for the included file, so executable statements inside valid PHP tags run in the including context; other bytes may be emitted as output. Code execution requires a reachable included file with attacker-controlled PHP code or another exploitable behavior. One possible chain is an upload or log-write weakness that places controlled PHP-tagged content in a file the application later includes. Treat that as a conditional chain, not an inherent property of every LFI.
Separately, php://filter applies a filter while opening a stream. In a vulnerable file-read or inclusion flow, a suitable filter can expose source text without executing it; whether a particular target is readable depends on wrapper behavior, permissions, and application configuration.
Why path sanitisation is the wrong fix
Stripping ../, appending a fixed extension, or prefixing a base directory does not establish that the final resource is an approved file. Encodings, absolute paths, platform-specific path rules, and stream wrappers can change how a value is interpreted. The structural fix is to remove user control over the resource name: let input select from a fixed set of application-defined keys, and reject anything outside that set.
If a design must resolve a filesystem path, canonicalize it with realpath() and verify directory-boundary containment as described in the path traversal guide. Then constrain the result to approved files. Account for symlinks and check/use races; a string prefix check is insufficient. An allowlist of fixed include targets is safer.
FAQ
It disables URL-aware wrappers for include/require. PHP documents it as off by default and deprecated since PHP 7.4. This reduces remote inclusion exposure but does not prevent local path traversal or unsafe local includes; keep it disabled and remove user control of include targets.
PHP 5.3.4 fixed null-byte termination in path handling. Do not use the absence of that legacy technique as a defense: untrusted include targets remain unsafe, and the allowlist fix does not depend on null-byte behavior.
require and the _once variants also include and parse the target; their failure and repeat-inclusion behavior differs, but they do not make an untrusted target safe. readfile() and file_get_contents() return data instead of parsing it as PHP, so an untrusted path there can cause traversal or disclosure rather than include-based code execution.