Authorization disclaimer. This walkthrough applies only to the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Test only systems you own or are explicitly authorized to assess.
Overview
The checkout API exposes an internal discount property when its state is retrieved, then accepts the same property from a client during checkout. Submitting a 100% discount reduces the lab’s jacket order to zero and bypasses the insufficient-funds condition.

Lab objective/setup
Sign in with the supplied wiener:peter account and buy the Lightweight l33t Leather Jacket. The relevant operation is POST /api/checkout; requesting the same resource with GET reveals additional checkout state.
What I observed
Adding the jacket and attempting checkout produced the expected insufficient-funds failure. Burp’s HTTP history identified the checkout API request and its JSON body.


Changing the method to GET for /api/checkout returned the serialized cart state. In addition to the selected products, the response contained chosen_discount with a percentage value of 0.

Why it is vulnerable
The server treats a client-supplied object as authoritative without restricting which properties may be bound to the checkout model. The read response discloses a server-controlled field, and the write operation accepts that same field. This combination lets the client assign a business-sensitive value that should be derived and enforced exclusively on the server.
Walkthrough in the authorized PortSwigger lab
- Add the jacket to the cart and attempt checkout once to capture
POST /api/checkout. - Send the request to Repeater and issue
GET /api/checkoutto inspect the returned object. - Copy the disclosed property shape into the original checkout JSON and set its percentage to
100:
1 | { |
- Submit the modified
POST /api/checkoutrequest. The server accepts the client-selected discount and creates the order.


Verification
The checkout response changes from insufficient funds to 201 Created, and the lab records the jacket purchase. This verifies that the additional JSON property, rather than a legitimate coupon workflow, controlled the final price.
Impact and defensive lesson
Mass assignment can expose any writable model property—not only discounts. Account roles, verification state, ownership identifiers, balances, and workflow flags can become security boundaries if blindly accepted from request bodies.
- Define request DTOs or explicit allow-lists for every write operation.
- Reject unknown properties instead of silently binding them.
- Calculate prices and discounts server-side from trusted product and promotion data.
- Keep response models separate from writable request models; do not assume a field is safe to accept merely because it is safe to display.
- Add authorization and invariant checks after binding and before persistence.
References
- PortSwigger lab: Exploiting a mass assignment vulnerability
- PortSwigger: Mass assignment vulnerabilities
- OWASP Mass Assignment Cheat Sheet
Provenance
Adapted and rewritten in English from the private migration source declared in the front matter. Technical observations and screenshots are retained from that authorized PortSwigger lab session; no behavior beyond the source evidence is asserted.