Forced Browsing
An unlinked URL is not a permission check.
What Is Forced Browsing?
A route exists, nothing in the interface links to it, and it answers anyone who guesses the path. Folder-name secrecy is not an access control. With no account, you'll run a content-discovery wordlist against a people platform and find an internal export route answering 200 OK with the full employee directory, no cookie or API key required. Then you add the gate it never had, a session and role check before a single row is read, and replay the request to a 403.
What You'll Learn in Forced Browsing
- Distinguish forced browsing from privilege escalation: the former assumes no session, the latter assumes the wrong session
- Recognize that a path segment like <code>/internal/</code> or <code>/admin/</code> is convention, not a control, the handler is the gate
- Understand that content-discovery tools (ffuf, dirbuster, gobuster) make path secrecy worthless within minutes
- Apply a session-presence and role check at the top of every handler that reads or writes sensitive data
- Audit the codebase for orphan routes that shipped for one tool, were superseded, and were never deleted
Forced Browsing — Training Steps
-
Size up the target
Bob is a financially motivated attacker. He finds companies that have left something exposed on the public internet, then sells what he pulls out or uses it to get at their money. Today he is targeting Kelvara, a people platform companies run their payroll and HR on. He starts where anyone would, on the public site, sizing the company up before he looks for a way in.
-
Map the API tree
Nothing on the public site is unusual: a sign-in, a product tour, a support page. But an app answers far more paths than it links to. Anything a developer left reachable stays reachable by anyone who goes looking, so Bob maps every path the portal's API actually responds to.
-
Open the export route
The one path that answered without a challenge is a URL like any other. Bob needs no tool for this: he types the discovered path straight into the browser and hits enter, the same as opening any page.
-
The whole directory, no login
The response is not an error page. The browser renders it inline: Kelvara's entire employee directory, thousands of records, handed to a request that carried no sign-in at all.
-
Knowledge check
You watched a guessed URL return sensitive data to a request with no credentials. Lock in why the endpoint was reachable.
-
The DLP alert lands
You own Kelvara's people portal. Overnight, outbound data-loss monitoring tripped on a response that carried the full employee directory, SSNs and salaries included, off the network. Security operations has emailed you the details.
-
Open the export handler
The handler that builds the employee export is what you need to change. Open it and look at what it does between the request arriving and the data going out.
-
Spot the missing gate
The handler reads every employee record and returns it. Read it top to bottom and look for the access check. There is nothing between the request and the query.
-
Knowledge check
You have seen the handler run from request to data with nothing in between. Lock in what actually keeps a route like this private.
-
Add the access check
Put a real gate at the top of the handler. It resolves the caller's session, confirms they hold the hr_admin role, and rejects everything else before the database query ever runs. The path stays the same; the check, not the folder name, is now what protects the data.
Security Framework Coverage
OWASP Top 10
- A01:2025 Broken Access Control
- A01:2021 Broken Access Control
CWE
- CWE-425 Direct Request ('Forced Browsing')
- CWE-862 Missing Authorization
CIS Controls
- CIS 16 Application Software Security
NIST CSF
- PR.AT-02 Individuals in specialized roles are provided with awareness and training so that they possess the knowledge and skills to perform relevant tasks with cybersecurity risks in mind
- PR.PS Platform Security