August 26, 2026
PortSwigger Lab Walkthrough: User ID Controlled by Request Parameter (Horizontal Privilege…
Introduction

By Vivek Yadav
4 min read
Introduction
Access control vulnerabilities are one of the most common — and most dangerous — categories of web application flaws. They're dangerous precisely because they're often simple to exploit but easy for developers to overlook. In this write-up, I'll walk through solving the "User ID Controlled by Request Parameter" lab from PortSwigger's Web Security Academy, which demonstrates a classic horizontal privilege escalation vulnerability.
If you're not familiar with the term: horizontal privilege escalation happens when a user is able to access data or perform actions belonging to another user of the same privilege level — not an admin, just some other regular account — because the application fails to properly verify ownership of the resource being requested.
This particular lab is a great beginner-friendly example because it shows the vulnerability in its rawest form: an ID value sitting right there in the request, just waiting to be changed.
Lab Objective
According to PortSwigger, this lab has a horizontal privilege escalation vulnerability on the user account page. To solve it, we need to obtain the API key belonging to the user carlos and submit it as proof of exploitation.
We're given valid low-privilege credentials to start with:
Username: wiener
Password: peterUsername: wiener
Password: peterSetting Up
Before touching the application, I fired up Burp Suite and made sure the browser traffic was routed through it, with intercept mode switched on. This lets me capture and inspect every request the browser sends, which is essential for spotting exactly how the app identifies "who" is requesting data.
Step-by-Step Walkthrough
1. Logging in
I navigated to the lab's login page and authenticated using the provided credentials, wiener:peter. Burp caught this request as it went out, along with the subsequent request that loads the account page after a successful login.
2. Inspecting the account page request
Once logged in, the app redirects to something like /my-account?id=wiener. This immediately caught my eye — the application is explicitly telling the server which account's data to return via a URL parameter, rather than relying purely on the session/cookie to determine identity.
That's the vulnerability, right there in plain sight.
3. Sending the request to Repeater
I right-clicked the captured /my-account?id=wiener request in Burp's HTTP history and sent it to Repeater, where I could freely modify and resend it without needing to go through the browser each time.
- Tampering with the
idparameter
In Repeater, I simply changed the value of the id parameter from wiener to carlos:
GET /my-account?id=carlos HTTP/2
Host: [lab-id].web-security-academy.net
Cookie: session=[my-session-token]GET /my-account?id=carlos HTTP/2
Host: [lab-id].web-security-academy.net
Cookie: session=[my-session-token]Note that I kept my own session cookie intact — I was still authenticated as wiener. The only thing I changed was which account's data I was asking for.
5. Sending the request
I hit Send, and the response came back with a 200 OK — and, more importantly, with carlos's account information rendered directly in the HTML response. This included his API key, sitting right there in plain text.
The server had authenticated me as wiener, but when it came time to decide whose account data to return, it just trusted the id parameter from the request instead of cross-checking it against the currently logged-in user. That's the whole bug.
6. Extracting the API key
I copied the API key value out of the response body.
7. Submitting the solution
Back on the lab page, I pasted the API key into the "submit solution" box and submitted it. The lab immediately flagged as solved.
Root Cause Analysis
This vulnerability boils down to a broken access control check — specifically, a missing authorization check on an authenticated endpoint.
The server correctly verifies that you're logged in (authentication), but it fails to verify that you're allowed to access the specific resource you're requesting (authorization). It effectively asks "is there a valid session?" instead of asking "does this session's user actually own the account with this ID?"
This is an incredibly common real-world mistake, and it maps directly to OWASP's Broken Access Control category — which has consistently ranked as the #1 risk in the OWASP Top 10 in recent years.
How This Should Be Fixed
For developers reading this, the fix is conceptually simple even if implementation details vary by framework:
- Never trust client-supplied identifiers for authorization decisions. The account ID being viewed should be derived from the authenticated session itself (e.g., pulled from the server-side session object), not read from a URL/query/body parameter.
- If an ID must be accepted from the client (e.g., admins viewing other users' accounts), the server should explicitly verify that the requesting user has permission to access that specific resource before returning any data.
- Apply the principle of least privilege and enforce object-level authorization checks on every request that touches user-specific data — this is sometimes referred to as Insecure Direct Object Reference (IDOR) prevention.
Key Takeaways
- Horizontal privilege escalation doesn't require any fancy exploitation technique — sometimes it's as simple as changing one value in a request.
- Always inspect how an application identifies "who's asking" versus "whose data is being requested" — when these two things aren't properly tied together, you've likely found an access control flaw.
- Burp Suite's Repeater tool is invaluable for this kind of manual testing; being able to quickly tweak and resend requests makes spotting these issues fast and intuitive.
This lab is a great reminder that not every vulnerability needs to be complex to be dangerous. A single unchecked parameter was enough to leak another user's private API key.
GoodByeeeee…..