Forced Browsing
debt(d5/e5/b5/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints.tools list includes nikto, dirbuster, owasp-zap, and semgrep — all specialist security tools rather than default linters or compilers. A standard linter won't flag missing authorisation middleware; you need a dedicated scanner or SAST tool to identify unprotected routes systematically.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix is conceptually simple ('every URL must verify authorisation'), but common_mistakes reveal the problem is pervasive: sequential IDs, missing server-side checks on file requests, forgotten backup files, robots.txt reliance. Fixing this requires auditing and updating every route/endpoint across the application, not a single-line swap.
Closest to 'persistent productivity tax' (b5). The applies_to scope is all web contexts in PHP 5.0+, and tags include authorisation and owasp-top10. Every new route or resource added to the codebase must be evaluated for proper authorisation checks. This is a persistent discipline tax on every developer adding endpoints, but it doesn't reshape the entire system architecture.
Closest to 'serious trap' (t7). The misconception field explicitly states the canonical wrong belief: 'Unpublished URLs are safe because attackers cannot guess them.' This directly contradicts how access control actually works and is a well-documented security anti-pattern. A competent developer new to security will naturally assume that not linking to a URL provides safety, making this a serious and dangerous cognitive trap.
Also Known As
TL;DR
Explanation
Forced browsing (also called direct object reference or insecure direct access) occurs when an attacker guesses or enumerates URLs for resources the application assumes are private due to obscurity — backup files, admin panels, uploaded files, API endpoints, or configuration dumps. The fix is never to rely on URL secrecy: every resource must enforce server-side authorisation regardless of how it is accessed. Tools like dirb, gobuster, and OWASP ZAP automate forced browsing discovery during pen tests.
Common Misconception
Why It Matters
Common Mistakes
- Generating download URLs or IDs sequentially — attackers enumerate ±1 from any known ID.
- No server-side authorisation check on direct file or resource requests — only the link is hidden.
- Backup files, old scripts, or admin panels deployed to the webroot and forgotten.
- Relying on robots.txt to hide admin paths — it advertises them to attackers.
Code Examples
// No ownership check — any user can download any invoice
public function download(string $filename): Response {
return response()->file(storage_path("invoices/$filename"));
}
// Use ID, not filename — enforce ownership
public function download(int $invoiceId): Response {
$invoice = Invoice::findOrFail($invoiceId);
if ($invoice->user_id !== auth()->id()) abort(403);
return response()->file(
storage_path("invoices/{$invoice->stored_filename}"),
['Content-Disposition' => "attachment; filename=invoice-$invoiceId.pdf"]
);
}