Handing in oddly shaped slips
Watch it happen
Mallory hands in a negative amount, a word where a number goes, and a slip hiding another slip. The teller trusts all three and the app’s defaults change.
Mallory walks in with a deposit slip. She is not guessing a password, she is about to watch what confuses the teller.
Mallory says: One deposit, please.In bank terms and app terms
| In the bank | In your app |
|---|---|
Are you exposed?
Your routes read request.json() and use the values straight away, with no schema. You merge or spread incoming objects into other objects (deepMerge, Object.assign, lodash merge). Sending null, -1, 0 or a very large number to your API gives a 500 error instead of a clean 400.
Validate every request body with a strict schema (types, ranges, lengths) and return 400 for anything else. Strip or reject __proto__, constructor and prototype keys before merging, and keep libraries like lodash up to date. Treat amounts, quantities and prices as server-checked numbers: reject negatives and zero where they make no sense.
It has happened to real companies
Lodash CVE-2019-10744 (2019) — Versions of Lodash before 4.17.12 had a prototype pollution flaw: the defaultsDeep function could be tricked into adding or modifying properties of Object.prototype using a constructor payload. Snyk, which reported it, said Lodash was downloaded over 80 million times a month.
jQuery CVE-2019-11358 (2019) — Prototype pollution in $.extend() affected jQuery versions before 3.4.0.
What it looks like in code
// GOOD: Parse the body into an explicit allowlist (unknown keys are dropped)
import { z } from "zod"
const UpdateProfile = z.object({
display_name: z.string().max(100).optional(),
avatar_url: z.string().url().optional(),
})
const body = UpdateProfile.parse(await request.json())
Ask your AI tool to fix it
Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.
Add strict schema validation (zod) to every API route that reads a request body: define exact types, min/max ranges and string lengths, strip unknown keys, and return a 400 with a clear message on failure. Reject negative or zero amounts where they make no sense, and make sure no code merges user-provided objects into other objects without removing __proto__, constructor and prototype keys.Where this comes from
The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.
- Input Validation Cheat SheetOWASPValidate server-side with allow-lists, types and min/max ranges
- Defining schemasZodSchema validation strips unknown keys by default
- JavaScript prototype pollutionMDNHow __proto__ keys in merged JSON pollute objects; schema validation as a fix
- Prototype Pollution Prevention Cheat SheetOWASPConstructor.prototype pollution; Object.create(null), Map/Set, freezing prototypes
- Snyk research team discovers severe prototype pollution security vulnerabilities affecting all versions of lodashSnykLodash defaultsDeep constructor payload; over 80 million downloads a month
- XSS in jQuery as used in Drupal, Backdrop CMS, and other productsGitHub Advisory DatabaseCVE-2019-11358: $.extend prototype pollution fixed in jQuery 3.4.0
Spot a mistake or something out of date? Report a correction · How these guides are made and checked
The free, open-source scanner checks for most of the problems in these guides.