PHP Local File Inclusion
Summary
This is the PHP-specific flavor of local file inclusion, and it's worth its own entry because PHP's include and require statements don't just read a file's contents the way most languages' file-reading functions do, they execute it as PHP code. That single fact turns an ordinary path-traversal-shaped bug into something considerably more dangerous. PHP also ships a family of built-in stream wrappers (php://, data://, expect://) that a vulnerable include/require call will happily process alongside ordinary file paths, and those wrappers open up techniques that don't exist in a language without PHP's specific wrapper system: reading a PHP file's raw source instead of its executed output, or in the right server configuration, executing arbitrary code from data supplied directly in the request with no file write required at all.
Top Affected Components / Targets
- PHP applications where a page, template, or module name parameter is passed directly into
includeorrequire - Legacy PHP applications built before
allow_url_includedefaulted to off, which is required for the most severe remote-code-execution variants
Common Attack Vectors
- Use the
php://filterwrapper with a base64-encode chain to read a PHP file's raw source code instead of its executed output, which is invaluable when the included file is PHP itself and would otherwise just run silently with no visible result - Where
allow_url_includeis enabled, use thedata://wrapper to supply a small PHP payload directly in the request URL and have it executed immediately, with no need to write anything to disk first - Use the
expect://wrapper, when the extension is installed, to execute an OS command directly through the include mechanism
Common Payloads
php://filter/convert.base64-encode/resource=index.phpto read a file's source rather than its outputphp://filter/read=convert.base64-encode/resource=/etc/passwdfor reading arbitrary files through the same wrapperdata://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==(a base64-encoded<?php phpinfo(); ?>) for direct code execution when remote inclusion is enabledexpect://idfor direct command execution where the expect extension is present
Detection Strategy
For any parameter feeding a PHP include or require call, the php://filter wrapper is the highest-value first test, since it works even when remote URL inclusion is disabled and directly proves the vulnerability by returning the target file's base64-encoded source in the response, rather than just an ambiguous behavioral difference. Where that succeeds, escalating to data:// or expect:// tests specifically for remote code execution, since a successful filter-read confirms the include is exploitable but not yet that it's exploitable for code execution.
Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.
False-Positive Notes
- A successful
php://filterread is strong, close to unambiguous proof, the base64-encoded content decodes to real, recognizable file content, which leaves little room for a false positive once decoded and verified. - The
data://andexpect://escalation paths depend on server configuration (allow_url_include, the expect extension) that varies by deployment, so their failure doesn't rule out the underlying LFI, it only means those specific escalation paths aren't available on this particular target.
How to Test
Manual Testing Methodology
Here is a systematic approach to identifying PHP Local File Inclusion vulnerabilities in a target application.
Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.
Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.
Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For PHP Local File Inclusion specifically, submit ../ sequences of increasing depth (../etc/passwd, ../../etc/passwd, and so on) alongside URL-encoded (%2e%2e%2f), double-encoded, and null-byte variants against every file-path parameter, and try both forward- and back-slash separators since one is sometimes filtered while the other isn't.
Compare the response against your baseline, looking specifically for the actual contents of a known system file (/etc/passwd, win.ini) appearing in the response, or a distinct error message (a different exception type or path echoed back) between a valid relative path and a traversal attempt.
Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For PHP Local File Inclusion, a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.
Real-World Impact
Real-World Impact
Path traversal lets attackers read, and sometimes write, files outside the directory an application intended to expose, usually by slipping ../ sequences into a file path parameter. Successful exploitation can expose source code, configuration files containing database credentials and API keys, and system files like /etc/passwd. In write scenarios, it can lead directly to code execution through a planted web shell.
In containerized environments, path traversal can escape an application's own file namespace to read secrets, environment variables, and mounted volumes belonging to other services entirely. In cloud deployments, it can expose provider-specific metadata files too.
This bug class becomes especially dangerous when combined with file inclusion. Reading a file is an information disclosure on its own, but if that file gets executed, the finding becomes remote code execution.
Prevention & Remediation
Prevention and Secure Coding
Preventing PHP Local File Inclusion takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.
Canonicalize and verify containment. Resolve the requested path to its canonical absolute form and check that it still falls inside an allowlisted base directory before touching the filesystem — check this after resolving symlinks and encoded sequences, not before.
Map to an internal ID, not a raw path. Where feasible, have user input select from a server-side allowlist or database record (an internal file ID) rather than being used as any part of a filesystem path directly.
Reject traversal sequences outright. Reject requests containing ../, .., URL-encoded variants (%2e%2e%2f), and null bytes rather than trying to strip them — stripping is a common source of filter-bypass bugs when done with a single non-recursive replace.
Least-privilege filesystem access. Run the file-serving process under an account with read access to only the directories it legitimately needs, so a traversal that gets past the application-layer check still hits an OS-level permission wall.
Disable directory listing and dangerous parsers. Serve static content through a web server configuration that has autoindexing disabled and doesn't execute uploaded files as scripts.