One Request That Changed Every Object
Deep-merging query params into shared config pollutes the prototype
Published Oct 29, 2026
Executive Summary
A vibe-coded Express app deep-merges query parameters into its shared config object so users can override a few settings. Because the merge is recursive and unguarded, a request containing __proto__ pollutes Object.prototype — and suddenly isAdmin is truthy everywhere. One visitor changes the app for everyone.
The Prompt
“Let users override a few app settings (theme, locale) by passing them as query parameters.”
The Flaw
A recursive merge that walks arbitrary keys copies req.query's own properties into config — including the magic key __proto__. Setting __proto__.polluted (or constructor.prototype.isAdmin) mutates Object.prototype, so every object in the process inherits the injected property. One crafted request flips security checks app-wide, and the pollution survives until the process restarts.
Risk & Impact
[Security] A single request can make authorization checks pass everywhere, because 'if (user.isAdmin)' now finds an inherited truthy property on every object.
Cost: App-wide security bypass — and the cause is nearly impossible to find by reading the request handler alone.
Code Comparison
❌ Vulnerable (AI generated)
❌ Vulnerable (AI generated)
✅ Hardened (production ready)
The Fix
Never deep-merge untrusted input into a shared object. Pick known keys into a fresh object, and freeze or guard prototypes where merging is unavoidable.
Prevention
- [linter] ESLint security plugins flag lodash.merge/_.merge and recursive extend on request data.
- [ci] A test that sends __proto__ or constructor.prototype as a query param must leave Object.prototype untouched — assert on a clean object's inherited props.
- [manual] Require an explicit key allowlist for any user-supplied object (rule 3), and forbid merging request data into globals (rule 6).
Why This Happened
Root cause: the prompt omitted Rule 3 and Rule 6 — the guardrails that would have caught this. See the full guide →
