After this lesson, you will be able to: Recognize, find, and fix Broken Access Control (OWASP A01): the most common web vulnerability, where users reach data or actions they should not.
Broken Access Control is the number-one item on the OWASP Top 10. It happens when the app fails to enforce what an authenticated user is allowed to do, letting them read other users' data, escalate privileges, or hit admin functions directly.
Access control decides who can do what. It breaks when the server trusts the client to enforce permissions, or checks them inconsistently. The classic form is IDOR (Insecure Direct Object Reference): the URL or request body names a resource id (/orders/1003) and the server returns it without checking that it belongs to the requesting user. Change the id to 1004 and you read someone else's order. Other forms: missing function-level checks (an admin endpoint reachable by a normal user), forced browsing to authenticated pages, and trusting a hidden form field or a client-side role flag.
Access control is found by testing, not scanning, because the server may respond normally; only the data is wrong.
Log in as a low-privilege user and capture a request that fetches your own resource (e.g. GET /api/orders/1003) in Burp Suite.
Change the id to one you do not own and resend. If you get someone else's data, that is an IDOR.
Try reaching admin-only endpoints (/admin, /api/users) as a normal user.
Look for permission decisions made in the client (hidden fields, disabled buttons, role flags in the response) and bypass them by calling the API directly.
Test both horizontal (other users' data at the same level) and vertical (privilege escalation to admin) access.
Enforce ownership and role on the server for every request.
// VULNERABLE: returns the order by id with no ownership checkapp.get('/api/orders/:id', requireAuth, async (req, res) => {const order = await db.order.findUnique({ where: { id: req.params.id } });res.json(order); // any logged-in user can read any order});// FIXED: scope every query to the authenticated user (deny by default)app.get('/api/orders/:id', requireAuth, async (req, res) => {const order = await db.order.findFirst({where: { id: req.params.id, userId: req.user.id },});if (!order) return res.status(404).json({ error: 'not found' });res.json(order);});// Rules: deny by default; check ownership AND role server-side on every// request; never trust client-supplied role/permission fields.
Pick the best answer.
Sign in and purchase access to unlock this lesson.