Description
Forced browsing (CWE-425 — Direct Request / Forced Browsing) is a vulnerability in which a web application restricts navigation through the user interface but fails to enforce corresponding access controls on the underlying server-side resources. An attacker bypasses the intended navigation flow by directly crafting or guessing URLs for pages, files, API endpoints, or other resources that the application assumes will only be reached through a specific UI sequence.
This vulnerability is a direct manifestation of the "security through obscurity" anti-pattern. Developers hide administrative interfaces, backup files, configuration exports, and sensitive API endpoints from normal users — but do not add authentication or authorization checks, assuming the resource won't be found. In practice, these resources are trivially discoverable through directory brute-forcing, JavaScript bundle analysis, search engine caching, and source code leaks.
Forced browsing falls under A01:2021 — Broken Access Control and is frequently found alongside other missing access control issues. It is distinct from path traversal (CWE-22) in that forced browsing navigates to valid, intended resources via their correct URLs — the problem is solely the absence of server-side authorization enforcement.
How It Works
A web application has an admin dashboard at /admin/dashboard that is not linked from any page a regular user can see. The developer assumes regular users will never encounter this URL. However, the page has no authentication check:
GET /admin/dashboard HTTP/1.1
Host: app.example.com
Cookie: session=<regular_user_session>
The server responds with 200 OK and a full administrative interface. The attacker discovered the URL through:
- Directory brute-forcing with tools like ffuf, gobuster, or feroxbuster using wordlists from SecLists (
Discovery/Web-Content/common.txt,raft-large-directories.txt). - JavaScript bundle analysis — modern SPAs embed all routes in the bundled JavaScript. Searching for
/admin,/internal, or/api/v1in the bundle reveals hidden paths. - Robots.txt and sitemap.xml — these files intended to guide search engine crawlers often explicitly list directories the developer wants hidden from the UI.
- Google dorking —
site:app.example.com inurl:adminorsite:app.example.com filetype:sqlcan surface indexed sensitive resources. - Backup and configuration files — developers commonly leave
backup.zip,config.bak,.env.old,database.sql.gz, orweb.config.bakin web-accessible directories.
$ ffuf -u https://app.example.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -mc 200,301,302,403
[Status: 200] /admin
[Status: 200] /backup.zip
[Status: 403] /config
[Status: 200] /.env.bak
A 403 response does not mean the resource is secure — it means the server knows the resource exists. Misconfigured servers often return 403 for directory listings but 200 for specific files within those directories.
Impact
- Access to administrative interfaces — user management, configuration changes, and system-level controls without authentication.
- Exposure of sensitive files — database dumps,
.envfiles, SSL private keys, and application configuration files containing credentials. - Source code disclosure — backup archives or
.gitdirectories reveal full application source code, enabling discovery of further vulnerabilities. - Bypass of workflow controls — reaching a confirmation page directly without completing the preceding steps (payment, verification).
- Internal API exposure — undocumented API endpoints intended only for internal service communication are exposed to the public internet.
Detection
- Run a directory and file brute-force using ffuf or gobuster with comprehensive SecLists wordlists against all discovered hostnames and subdomains. Include file extensions:
.php,.bak,.zip,.sql,.env,.conf,.log,.old. - Analyze the JavaScript bundle — download and beautify the minified JS with a tool like js-beautify or
prettier, then grep for route definitions, API paths, and hardcoded URLs (/admin,/internal,/api/v). - Review robots.txt and sitemap.xml — these files are explicitly designed to list URL paths and frequently reveal sensitive directories.
- Test all discovered endpoints with low-privileged sessions — for any URL that returns 403 or redirects to a login page, test bypasses:
X-Original-URLheader,X-Rewrite-URLheader, URL path normalization (/admin/,/ADMIN,/admin/../admin), and HTTP method switching. - Check for exposed version control directories — request
/.git/HEAD,/.git/config, and/.svn/entries. A successful response allows full source code recovery with tools like git-dumper.
Remediation
Implement server-side authorization on every endpoint. Authentication and authorization must never rely on a resource being unlinked — they must be enforced by server-side middleware on every request, regardless of how the URL was obtained.
Remove sensitive files from web-accessible directories. Database dumps, backup archives, .env files, and configuration files must never reside in the web root or any directory served by the application. Store them outside the document root or in an access-controlled object store.
Disable directory listing. In nginx, ensure autoindex off; is set. In Apache, use Options -Indexes. A disabled directory listing does not protect individual files but removes a discovery vector.
Restrict access to development and administrative paths at the network level. Admin interfaces should be accessible only from specific IP ranges, internal networks, or VPN endpoints — in addition to application-level authentication.
Audit and remove legacy files. Establish a deployment process that prevents backup files, .git directories, and configuration drafts from reaching production. Use a .gitignore to exclude sensitive files and verify the web root after every deployment.
