CWE-425, the direct request weakness often called forced browsing, applies when a web application does not enforce appropriate authorization on all restricted URLs, scripts or files.
It hits any web app with admin pages, reports, exports, uploads or backups. The common mistake is protecting the link instead of the page.
How it happens
A developer hides the admin link from regular users. The route behind it still answers to anyone who knows the address. Attackers guess names like /admin, /export, /backup, or find them in JavaScript, old links or search engines.
// Vulnerable: no authorization check on the route
app.get("/admin/users", (req, res) => {
res.json(db.listUsers());
});
MITRE's observed examples show the range of impact:
- A document collaboration tool prevented listing hidden directories but not direct requests to files in them (CVE-2022-29238).
- Authentication bypass through a direct request (CVE-2004-2144).
- An infinite loop or information leak triggered by direct requests (CVE-2005-1892).
- Another authentication or authorization bypass via direct request (CVE-2004-2257).
What an attacker gains
The record lists a wide set of consequences: reading application data, modifying application data, executing unauthorized code or commands, and gaining privileges or assuming identity. What they get depends on what sits behind the unprotected URL.
How to find it
The record lists no detection methods, so use these:
- Build a list of every route, including admin, debug and export paths. Compare against the routes that have an access check.
- Request each URL while logged out, and again as a low privilege user.
- Run a dynamic scanner against a staging copy of the app to probe common paths.
- Review static files and uploaded content directories. Files are routes too.
How to fix it
- Check authorization on the server for every request. Do not rely on hidden links or client side logic.
- Deny by default. Apply an authentication and role check to the whole route group, and open specific routes deliberately.
- Protect files, not just pages. Serve sensitive files through a handler that checks permission, or keep them outside the web root.
- Remove leftovers. Delete backups, old versions and test pages from production.
- Test it. Add automated tests that call each protected URL without permission and expect a 401 or 403.
// Fixed: group level check, deny by default
const admin = express.Router();
admin.use(requireLogin);
admin.use(requireRole("admin"));
admin.get("/users", (req, res) => res.json(db.listUsers()));
app.use("/admin", admin);
Try it yourself
The DAST demo walks through how a scanner probes a running web app for exposed paths.
Click through it at your own pace, or open it full screen.
Quick check
Is removing a link from the menu a fix?
No. The server still answers the direct request. Authorization has to be enforced at the route.
What does deny by default mean here?
New routes require login and a role unless someone deliberately marks them public.