File inclusion
File inclusion vulnerabilities occur when user-controlled input is passed to a file-loading function without sufficient validation. Local File Inclusion reads files from the server filesystem. Remote File Inclusion loads and executes code from a remote URL. Both lead to full code execution with the right conditions. Detection here stops at confirmation: exploitation is covered in the file inclusion exploitation section.
- LFI path traversal reads files outside the webroot using
../sequences at varying depths. - Encoding bypasses use URL-encoded and double-encoded traversal when basic sequences are stripped.
- Extension appending bypass uses null bytes or path tricks against applications that append .php.
- RFI detection points the parameter at a controlled URL and watches for an incoming connection.
- Automated fuzzing with ffuf and LFI wordlists tests all traversal variants against a confirmed parameter.
Look for parameters named page, file, path, include, template, view, doc, or lang during parameter crawling: these are the most common carriers.
Identify File Loading Parameters
Check the application's URL structure and form inputs for parameters that accept filenames or paths:
4823
3102
Different response sizes for different parameter values strongly suggest the parameter is loading different files. That's your LFI test target.
LFI Detection: Path Traversal
Test path traversal sequences to read files outside the intended directory. Start with a known target file:
root:x:0:0:root:/root:/bin/bash
Content from /etc/passwd in the response confirms LFI. If nothing shows on the basic traversal, the application may be stripping ../ sequences. Try URL-encoded and double-encoded variants:
LFI with Extension Appending
Some applications append .php or another extension to the parameter value. Use a PHP null byte or path tricks to bypass on older PHP versions:
Null byte truncation works on PHP 5.3 and earlier. On newer PHP, use path length attacks or look for wrapper-based bypasses instead.
RFI Detection
Remote File Inclusion requires allow_url_include = On in PHP config, which is off by default in modern installs. Test by pointing the parameter at an external URL you control:
An incoming HTTP request on your listener confirms RFI: the server fetched a remote URL based on your input. This is also a confirmed SSRF path through the file inclusion vector.
Automated Fuzzing
Use ffuf with a dedicated LFI wordlist to test multiple traversal variants across a parameter quickly:
Set -fs to the normal response size so only responses with different content (indicating a successful file read) are shown. Confirmed LFI moves to local file inclusion exploitation for sensitive file extraction and path to RCE.
Non-PHP File Inclusion
File inclusion is not limited to PHP. Any framework that serves files or includes templates based on user input is a potential target. The traversal payloads are the same, but the vulnerable function and target files differ by language.
Java / Spring
Spring controllers that use path variables to serve files are vulnerable when the input is not sanitized. The @PathVariable annotation passes the raw URL segment to the handler. Spring normalizes ../ in the URL path before routing, but if the application reads the path from a query parameter or request body instead, traversal works. Also check ResourceHttpRequestHandler configurations serving static resources from user-controlled paths.
root:x:0:0:root:/root:/bin/bash
Use --path-as-is with curl to prevent it from normalizing the ../ sequences before sending. Without it, curl resolves the path client-side and the traversal never reaches the server.
Node.js / Express
Express applications using res.sendFile() or res.download() with user-controlled paths are vulnerable if the root option is not set. Without a root, the path is resolved relative to the process working directory. The path.join() function does not prevent traversal, it resolves ../ sequences as valid path components. Target /etc/passwd on Linux or package.json to confirm the application root.
root:x:0:0:root:/root:/bin/bash
Reading package.json reveals dependencies and version info. Look for known vulnerable packages. Read .env one directory up for database credentials and API keys.
Python / Flask
Flask applications using send_file() or send_from_directory() with unsanitized user input allow traversal. send_from_directory() is safer because it restricts to a base directory, but only if the developer does not concatenate the path manually before calling it. Werkzeug (Flask's WSGI layer) blocks traversal in the URL path by default, so the vulnerable parameter is usually in the query string or POST body.
root:x:0:0:root:/root:/bin/bash
.NET
.NET applications serving files through File(), PhysicalFile(), or custom handlers are vulnerable when the path comes from user input. IIS normalizes path traversal in URLs by default, so the traversal typically needs to be in a query parameter or POST body. Target web.config for connection strings and appsettings.json for application secrets.
Windows paths use backslashes, so test both ../ and ..\ (URL-encoded as ..%5C). Some .NET middleware normalizes forward slashes to backslashes, making both forms work. The web.config file often contains database connection strings, SMTP credentials, and custom application keys in the appSettings or connectionStrings sections.
References
-
SecLists: LFI WordlistsREPO: SecLists: LFI Wordlists, github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI (opens in new tab)
LFI traversal payload lists including Jhaddix and common variants
-
PayloadsAllTheThings: File InclusionREPO: PayloadsAllTheThings: File Inclusion, github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion (opens in new tab)
LFI and RFI payload collection including wrapper-based bypasses