broken-access-control
Detects missing ownership checks, broken role enforcement, and IDOR vulnerabilities that let users access other users' resources. Use when writing code that checks authorization, enforces resource own
SKILL.md.claude/skills/broken-access-control/SKILL.md
GitHubBroken Access Control Security Check (A01:2025)
What this checks
Protects against unauthorized resource access caused by missing ownership checks or
role enforcement. Exploitation leads to horizontal/vertical privilege escalation.
For SSRF (server-side request forgery), see the dedicated ssrf skill.
Vulnerable patterns
- Resource lookup by caller-supplied identifier with no ownership predicate before the row is returned, mutated, or acted on
- Privileged or admin route mounted with no role check at the route/controller declaration
- Ownership check that runs after the resource has already been fetched and consumed by downstream logic
- Ownership failure that responds with a distinct "forbidden" status, leaking that the resource exists
Fix immediately
Flag the vulnerable code and explain the risk. Then suggest a fix that establishes these properties:
- Every resource lookup by caller-supplied identifier is gated before the resource is returned, mutated, or acted on. The gate binds the row to the authenticated caller — an ownership predicate for per-instance access, or a role predicate for role-scoped access. The check can live in a handler, interceptor, filter, annotation, decorator, or middleware — anywhere, as long as it runs before the data is used.
- Privileged routes enforce role membership through a reusable, centrally-declared
mechanism (middleware, filter chain, annotation, decorator, policy) attached at
the route or controller declaration. Ad-hoc
if role != "admin"checks inside handler bodies are brittle — they can be forgotten on a new route and they're invisible at a glance. - Ownership failures return an indistinguishable "not found" response (HTTP 404). Returning 403 leaks that the resource exists. Role-missing failures on a privileged route may still return 403 — the route itself is public knowledge, so only the instance-level check needs to hide behind 404.
Translate these principles to the audited file's language and framework. Use the documented authorization or policy mechanism for that stack; do not invent ad-hoc checks in handler bodies.
Verification
Confirm these properties hold (language-agnostic):
- Every resource lookup by caller-supplied identifier is gated by an ownership or role predicate before the resource is returned, mutated, or acted on — regardless of whether the check lives in a handler, interceptor, filter, annotation, decorator, or middleware
- Privileged routes enforce role membership through a reusable, centrally-declared mechanism (middleware, filter chain, annotation, decorator, policy) attached at the route/controller declaration — not via ad-hoc
ifchecks inside individual handler bodies - Ownership (per-instance IDOR) failures return an indistinguishable "not found" response (e.g. HTTP 404) rather than a distinct "forbidden" response, to prevent resource enumeration. Role-missing failures on a privileged route may use 403 because the route itself is public knowledge
References
- CWE-284 (Improper Access Control)
- CWE-862 (Missing Authorization)
- CWE-863 (Incorrect Authorization)
- CWE-918 (Server-Side Request Forgery)
- OWASP A01:2025 Broken Access Control