Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type Server-Side Prototype Pollution
Difficulty Practitioner
Objective Pollute the server-side Object.prototype via a JSON merge in the address update endpoint to set isAdmin: true and delete carlos

Privilege Escalation via Server-Side Prototype Pollution

I logged in as wiener:peter and found a billing and delivery address form:

Screenshot

Intercepting the form submission:

Screenshot

The request POSTs JSON to /my-account/change-address, and the response returns a JSON representation of the updated user object — including isAdmin: false. POST/PUT endpoints that accept JSON and echo back the modified object are the prime candidates for server-side prototype pollution, because the response shows whether injected properties propagate.

Server-side prototype pollution runs in Node.js — there's no DevTools console on the server. The oracle is the HTTP response: if a property injected via __proto__ appears in the server's JSON response, pollution is confirmed. JSON.parse() in Node.js treats __proto__ as a real key; if the app then merges the parsed object using an unsafe recursive merge (common in Express apps), Object.prototype gets polluted process-wide — affecting every object for all users until the server restarts.

Adding a __proto__ key with a benign test property:

{
    "address_line_1": "Wiener HQ",
    ...,
    "__proto__": {
        "teto": "miku"
    }
}
Screenshot

Response:

{"username":"wiener",...,"isAdmin":false,"teto":"miku"}

teto: "miku" appeared in the response — never in the original user object, inherited from the prototype. Pollution confirmed. The response also handed us the gadget: isAdmin: false was visible in the user serialization, meaning the access control check reads it from the object. We can override it via the prototype.

Injecting isAdmin: true:

{
    "__proto__": {
        "isAdmin": true
    }
}

Response: "isAdmin":true. Refreshing the page:

Screenshot

Admin panel link appeared. Navigating to /admin:

Screenshot

Deleted carlos.

Lab solved :P

Resources