{
    "slug": "broken_access_control",
    "term": "Broken Access Control",
    "category": "security",
    "difficulty": "intermediate",
    "short": "Failure to enforce what authenticated users are allowed to do — the #1 OWASP vulnerability, enabling privilege escalation and data exposure.",
    "long": "Broken access control covers: horizontal escalation (accessing another user's data by changing an ID), vertical escalation (accessing admin functions as a regular user), missing function-level checks (assuming UI hiding is sufficient), insecure direct object references (IDOR), CORS misconfigurations, and JWT tampering. In PHP applications, enforce access checks server-side on every request — never rely on hidden form fields, client-side role checks, or obscure URLs. Centralise authorisation logic in a dedicated gate or policy class rather than sprinkling ad-hoc checks throughout controllers.",
    "aliases": [
        "BAC",
        "access control failure",
        "authorisation bypass"
    ],
    "tags": [
        "owasp-top10",
        "authorisation",
        "cwe-284"
    ],
    "misconception": "Hiding URLs or buttons in the UI prevents unauthorised access. Security through obscurity is not access control — any URL accessible to one authenticated user can be accessed directly by another, bypassing the UI entirely.",
    "why_it_matters": "Broken access control is the #1 OWASP vulnerability — it means users can access data or actions they should not. A single missing authorisation check can expose every record in your database to any authenticated user.",
    "common_mistakes": [
        "Hiding links in the UI instead of enforcing authorisation server-side — obscurity is not access control.",
        "Checking authentication (are you logged in?) but not authorisation (are you allowed to do this?).",
        "Using sequential IDs and assuming users will not guess other users' resource IDs (IDOR).",
        "Applying access control in middleware but bypassing it in API routes or admin controllers."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "idor",
        "privilege_escalation",
        "principle_of_least_privilege",
        "mass_assignment"
    ],
    "prerequisites": [
        "idor",
        "principle_of_least_privilege",
        "session"
    ],
    "refs": [
        "https://owasp.org/Top10/A01_2021-Broken_Access_Control/",
        "https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html"
    ],
    "bad_code": "// Access control only in the UI — not enforced server-side:\nrouter()->get('/admin/users', [AdminController::class, 'index']);\n// Middleware checks role for /admin/* in the UI\n// But direct API call to /api/users/export has no role check\n// Attacker bypasses UI, calls API directly — full data exposure",
    "good_code": "// RBAC check on every protected route:\npublic function show(int $id): Response {\n    $resource = Resource::findOrFail($id);\n\n    // Check ownership OR admin role:\n    if ($resource->user_id !== auth()->id() && !auth()->user()->isAdmin()) {\n        abort(403, 'Forbidden');\n    }\n\n    return response()->json($resource);\n}\n\n// Or policy-based (Laravel):\npublic function show(User $user, Resource $resource): bool {\n    return $user->id === $resource->user_id || $user->isAdmin();\n}\n// Controller: $this->authorize('show', $resource);",
    "quick_fix": "Check authorisation on every request server-side: does the authenticated user own or have permission for this specific resource?",
    "severity": "critical",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/broken_access_control",
        "html_url": "https://codeclaritylab.com/glossary/broken_access_control",
        "json_url": "https://codeclaritylab.com/glossary/broken_access_control.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Broken Access Control](https://codeclaritylab.com/glossary/broken_access_control) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/broken_access_control"
            }
        }
    }
}