Privilege Escalation
debt(d8/e6/b7/t7)
Closest to 'silent in production' (d8) — Semgrep can catch obvious patterns like role from $_GET, but most privilege escalation flaws (missing ownership checks, mass assignment, trusting session role) are silent until exploited. Slightly better than d9 because some patterns are linter-catchable.
Closest to 'cross-cutting refactor' (e6) — quick_fix says verify role/permission on every sensitive action server-side, which means auditing and patching every controller/handler that performs sensitive actions. Between multi-file refactor (e5) and codebase-wide (e7).
Closest to 'strong gravitational pull' (b7) — authorisation applies across web/api/cli contexts and every sensitive action must respect it; consistent access-control shapes how new features are added throughout the codebase.
Closest to 'serious trap' (t7) — misconception states devs assume privesc requires a separate exploit, but mass assignment, JWT claim trust, and session-stored roles allow direct escalation. The 'obvious' check-once-at-login pattern contradicts the need for per-action server-side verification.
Also Known As
TL;DR
Explanation
Privilege escalation occurs when authorisation decisions are based on attacker-controllable data — a URL parameter, POST field, or cookie value — rather than server-side session state. Example: checking $_GET['admin'] === 'true' instead of $_SESSION['role'] === 'admin'. The fix is always to derive permissions exclusively from server-side state that the user cannot tamper with.
How It's Exploited
# If server accepts alg:none, attacker is now admin
Common Misconception
Why It Matters
Common Mistakes
- Trusting user role or is_admin flags from client-supplied data (cookies, JWT payloads, form fields) without server-side verification against authoritative state.
- Not checking ownership when performing actions on resources — user A can modify user B's data by changing the resource ID.
- Mass assignment vulnerabilities that allow setting role or is_admin through form fields.
- Admin functionality that validates the role only in the UI, not in the server-side handler.
Code Examples
// Role stored in JWT payload — user can edit it client-side
$role = $jwtPayload['role']; // never trust client-supplied roles
if ($role === 'admin') { grantAdminAccess(); }
// Always fetch authoritative role from the database
$user = User::findOrFail($jwtPayload['sub']); // look up by ID only
if ($user->role === 'admin') { grantAdminAccess(); }
// Or use signed, server-verified JWT with short expiry
// Never embed mutable authorisation claims in long-lived tokens
Tags
Edits history 1 edit
- common_mistakes PF Media Bot Claude Opus 4.5 · 19 May 2026