criticalAuthentication

Broken Access Control and Missing Authorization

What Is This Vulnerability?

Broken access control occurs when an application does not properly enforce what authenticated users are allowed to do. Even with authentication in place, the absence of authorization checks means regular users can access admin functionality, modify other users' data, or perform actions beyond their intended role. This is consistently ranked among the top web application vulnerabilities.

Why It Happens

Authorization logic is often scattered across the codebase rather than centralized. Developers add authentication but forget per-endpoint authorization. Role checks are implemented inconsistently, with some routes checking permissions and others relying on UI hiding (not showing the button) as the only control. API endpoints are added without mirroring the restrictions present in the frontend.

Example Code

Vulnerableroutes/admin.ts
app.put("/api/users/:id/role", requireAuth, async (req, res) => {
  const { role } = req.body;
  await db.query(
    "UPDATE users SET role = $1 WHERE id = $2",
    [role, req.params.id]
  );
  res.json({ success: true });
});

app.get("/api/admin/analytics", requireAuth, async (req, res) => {
  const data = await getAnalyticsData();
  res.json(data);
});
Fixedroutes/admin.ts
import { requireAuth, requireRole } from "@/middleware/auth";

app.put(
  "/api/users/:id/role",
  requireAuth,
  requireRole("admin"),
  async (req, res) => {
    const { role } = req.body;
    const allowedRoles = ["user", "editor"];
    if (!allowedRoles.includes(role)) {
      return res.status(400).json({ error: "Invalid role" });
    }
    await db.query(
      "UPDATE users SET role = $1 WHERE id = $2",
      [role, req.params.id]
    );
    res.json({ success: true });
  },
);

app.get(
  "/api/admin/analytics",
  requireAuth,
  requireRole("admin"),
  async (req, res) => {
    const data = await getAnalyticsData();
    res.json(data);
  },
);

How Hackers Exploit It

Attackers authenticate as a regular user and then manually craft requests to admin-only endpoints. They modify request parameters (changing a user_id or role field) to escalate privileges or access restricted resources. Tools like Burp Suite make it trivial to replay and modify requests. If the API only hides features in the UI without server-side checks, any API call the admin can make is available to all users.

How to Fix It

Implement a centralized authorization middleware that checks roles and permissions on every request. Deny access by default and explicitly grant permissions per role. Never rely on client-side hiding as a security measure. Write authorization tests that verify regular users cannot access admin endpoints. Use a policy-based framework like CASL or a database-level row security policy.

Frequently Asked Questions

What is the difference between authentication and authorization?
Authentication verifies who a user is (login with username and password). Authorization determines what they are allowed to do (which endpoints, data, and actions they can access). You need both. An authenticated user without proper authorization checks can still cause serious damage.
How do I test for broken access control?
Create accounts with different roles (admin, editor, regular user). Log in as each role and attempt to access every API endpoint. Verify that restricted endpoints return 403 Forbidden for unauthorized roles. Automate these checks in your test suite to catch regressions when new endpoints are added.
Is hiding UI elements a valid access control mechanism?
No. Hiding buttons or menu items only prevents casual discovery. Any user with browser developer tools or an HTTP client can call the underlying API directly. Access control must always be enforced on the server side, regardless of what the frontend displays.

Related Security Topics

Check Your Code for This Vulnerability

Run a free scan to check if your site is affected by broken access control and missing authorization.