The Exploit HQ

Web Application Security for Beginners · lesson 2 · 2026-08-24 · updated 2026-10-12

File Inclusion & Path Traversal — Web Application Security for Beginners (LFI/RFI)

Before you start

Welcome back to The Exploit HQ, and to part two of our beginner series on web application security. Just like last time, you need zero experience to follow along.

In part one we changed a number and saw a stranger’s shopping cart. Today we do something that feels almost magical, and a little scary. We are going to make a website hand us files from deep inside its own computer, files it was never meant to show anyone.

First, the plain words. Many web pages are not one single file. To build one page, the app quietly loads several smaller files and stitches them together.

What is file inclusion?

The app decides which file to load, and very often the file’s name is sitting right there in the web address, after the letters p-a-g-e and an equals sign. That little setting is meant to load the app’s own pages. But if the app trusts whatever name we put there, then we, the visitor, get to choose the file. And that is the whole problem.

This flaw comes in a few flavours, and the names sound scarier than they are.

LFI, RFI, and path traversal

L F I, local file inclusion, means we read a file that already lives on that same computer. R F I, remote file inclusion, is the nastier cousin, where the app loads a file from somewhere else on the internet, even one the attacker controls. And path traversal is the trick we use to move around the disk. Those two little dots and a slash, dot dot slash, simply mean, go up one folder, exactly like the back button in a file browser. Do it enough times and you reach the very top of the disk.

You might be thinking, so what, it is just a file. Here is why it matters.

Why should you care?

The same trick can read the server’s list of user accounts, its configuration files, which very often contain database passwords in plain text, and the app’s own private source code. And in the worst case, remote file inclusion, the server can be fooled into running an attacker’s code, which is a complete takeover. This family is tracked by the security world as path traversal, CWE twenty two, and file inclusion, CWE ninety eight, and it lands inside O-WASP’s number one category, broken access control, the very same top category from part one.

For the demo we will use our own local practice app, and just three simple tools.

The tools we’ll use

curl is that small program from part one that sends a web request straight from the terminal, like a browser with no window. cookies dot txt is a file holding our logged-in session for our own practice app, think of it as the wristband from part one that proves we are allowed in. And grep is a tiny helper that reads a big pile of text and keeps only the lines we ask for, so the answer is easy to read.

Our practice target is DVWA, the Damn Vulnerable Web Application, running only on our own machine. It has a page whose whole job is file inclusion. Let’s break down that page’s address before we touch it.

The vulnerable page

http://127.0.0.1:8080/vulnerabilities/fi/?page=include.php
Part What it does
http://127.0.0.1:8080 our OWN computer — 127.0.0.1 always means ‘this machine’
/vulnerabilities/fi/ the File Inclusion practice page (fi = file inclusion)
?page=include.php which file to load — normally one of the app’s OWN pages
?page=/etc/passwd …but nothing stops us naming a DIFFERENT file

So one-two-seven dot zero dot zero dot one is our own computer, nobody else’s. The f-i page is built for file inclusion practice. And that page equals part is where the app expects the name of one of its own pages. The flaw is that it never checks, so we can quietly ask for a completely different file instead.

Let’s break down the actual command we’ll run, piece by piece.

Step 1 — ask for a file we shouldn’t get

curl -s -b cookies.txt ".../fi/?page=/etc/passwd" | grep -E "^root:|^www-data:|^mysql:|^daemon:"
Part What it does
curl -s send a web request quietly, with no progress bar
-b cookies.txt send our saved login session — the wristband — so the app lets us in
?page=/etc/passwd instead of an app page, ask for the system’s user-account file
| grep -E "^root:…" from the reply, keep only the real account lines so it’s readable

In plain terms, we prove we are logged in with our wristband, then we ask the page to load the file called etc passwd, which is the computer’s own list of user accounts. Then grep tidies the answer down to the interesting lines. Let’s open the terminal and type it together.

Type it with me, slowly.

curl -s -b cookies.txt "http://127.0.0.1:8080/vulnerabilities/fi/?page=/etc/passwd" | grep -E "^root:|^www-data:|^mysql:|^daemon:"

Look at that. Those are real user accounts from inside the server. root is the all-powerful administrator. www dash data is the account that runs the website. mysql is the database account. This is the etc passwd file, a file that is supposed to stay on the server, out of sight. The page was only meant to load its own pages, yet it happily read a private system file just because we asked.

Now, in that first command we handed over a full, exact path. But often an app only lets us pick from its own folder. So how do we escape that folder? We climb, using dot dot slash.

Step 2 — climb out with path traversal

curl -s -b cookies.txt ".../fi/?page=../../../../../../etc/passwd" | grep -E "^root:|^www-data:|^mysql:|^daemon:"
Part What it does
?page=../../../../../../ each ../ climbs UP one folder — repeat until we reach the disk’s top
etc/passwd from the top, walk back down into the same secret file
the rest identical to before — same wristband, same tidy-up with grep

Each dot dot slash steps us up one folder, toward the top of the disk. We add a few extra, just to be sure we reach the very top, and then we walk down into etc passwd. Extra climbs at the top do no harm, you simply cannot go higher than the top.

Here we go.

curl -s -b cookies.txt "http://127.0.0.1:8080/vulnerabilities/fi/?page=../../../../../../etc/passwd" | grep -E "^root:|^www-data:|^mysql:|^daemon:"

The exact same secret file, but this time we reached it by climbing folders with dot dot slash, instead of typing the full path. That climbing move is what the word path traversal means. And remember the scariest cousin, remote file inclusion. If the server allowed it, that page equals part could point at a file on the attacker’s own website, and the server would fetch and run it. We will not demo that one, because it needs a second machine, but it is the very same root cause, an app trusting a file name it should never trust.

So how do you find this flaw, and how is it fixed?

Find it, and fix it

To find it, you do exactly what we did. Put a path where the app expects a page name, try climbing with dot dot slash or a full path, and see if a file you should not get comes back. To fix it, the golden rule is, never feed a visitor’s text straight into a command that opens or includes a file. Instead, keep a short allow list of the exact pages that are permitted, reject everything else, and switch off the setting that lets the app load files from the internet. That closes the whole hole.

And one rule, every single time.

Before you go

Only ever test apps you own, or have clear written permission to test. Our DVWA runs only on our own machine, and it was built for exactly this kind of safe, legal practice. In part three, we will look at information disclosure, all the little ways an app leaks secrets it never meant to. Thanks for learning with The Exploit HQ, and I’ll see you there.