Intro to File Inclusions
Many back-end stacks (PHP, JavaScript/Node, Java, .NET, and others) use HTTP parameters or path segments to choose which resource is rendered. That keeps templates small and pages dynamic. If the resolved path is built from user-controlled input without strict validation, an attacker can point the application at arbitrary local files—Local File Inclusion (LFI)—or, where the API allows it, remote resources (Remote File Inclusion, RFI, when applicable).
Where LFI often shows up
Templating is a common pattern: a shell page (header, nav, footer) stays fixed while a parameter selects the “inner” content. Example: /index.php?page=about where index.php includes about.php (or similar) based on page. Because the dynamic segment is often attacker-influenced, the include primitive may load unintended paths.
Impact
- Source code disclosure — aids further review and chained bugs.
- Sensitive data exposure — configs, keys, credentials, backups.
- Remote code execution (RCE) — possible when the primitive executes included content (e.g. PHP
includeon attacker-controlled paths) or when read access enables another exploit chain.
Even read-only disclosure can compromise the application or adjacent systems if secrets leak.
Vulnerable patterns (by stack)
The core mistake is the same everywhere: user input flows into a file path or include target with insufficient normalization, allowlisting, or sandboxing.
PHP
include(), include_once(), require(), require_once(), file_get_contents(), and related APIs load paths. Passing $_GET['language'] (or similar) straight through is unsafe:
if (isset($_GET['language'])) {
include($_GET['language']);
}
Other dangerous sinks include fopen(), readfile(), etc., depending on whether the goal is execution vs disclosure.
Node.js
fs.readFile with a user segment under path.join(__dirname, req.query.language) still breaks out if language contains ../:
if (req.query.language) {
fs.readFile(path.join(__dirname, req.query.language), function (err, data) {
res.write(data);
});
}
Express res.render with an interpolated path is also risky when the parameter selects a template file:
app.get("/about/:language", function (req, res) {
res.render(`/${req.params.language}/about.html`);
});
Java (JSP)
<jsp:include> or <c:import> driven by request parameters passes attacker-controlled locations into the view layer:
<c:if test="${not empty param.language}">
<jsp:include page='<%= request.getParameter("language") %>' />
</c:if>
<c:import url='<%= request.getParameter("language") %>'/>
.NET
Response.WriteFile, @Html.Partial, server-side <!--#include file="..."-->, and related APIs are unsafe when the path comes from Query, route data, or form fields without an allowlist.
Read vs execute vs remote
Primitives differ in whether they only read bytes, execute server-side code, or accept remote URLs:
| Stack | Function / API | Read content | Execute | Remote URL |
|---|---|---|---|---|
| PHP | include() / include_once() | Yes | Yes | Yes |
| PHP | require() / require_once() | Yes | Yes | No |
| PHP | file_get_contents() | Yes | No | Yes |
| PHP | fopen() / file() | Yes | No | No |
| Node.js | fs.readFile() | Yes | No | No |
| Node.js | res.sendFile() (typical) | Yes | No | No |
| Node.js | res.render() | Yes | Yes* | No |
| Java | jsp:include | Yes | No | No |
| Java | c:import | Yes | Yes | Yes |
| .NET | @Html.Partial() | Yes | No | No |
| .NET | @Html.RemotePartial() | Yes | No | Yes |
| .NET | Response.WriteFile() | Yes | No | No |
| .NET | SSI <!--#include ...--> | Yes | Yes | Yes |
*Template engines may execute logic embedded in templates; treat user-influenced template paths as high risk.
Why this matters: execution-capable includes widen impact to RCE; read-only leaks still expose secrets and logic. In code review, tag any user-controlled input reaching these sinks.
Scope note
Many lab-style materials emphasize PHP on Linux because payloads and log poisoning chains are well documented. The root cause (unsafe path composition) is framework-agnostic; defenses (allowlists, canonical paths, no direct filesystem mapping from HTTP parameters) apply everywhere.