javascript / intermediate
Snippet
Prototype Pollution Defense in React State Update Handlers
When dynamically setting nested object state in React from dynamic user keys, attackers could exploit property traversal to pollute the JavaScript `Object.prototype`. Using a Set of forbidden identifier keys alongside `Object.freeze` and prototype-less objects created with `Object.create(null)` prevents prototype pollution attacks.
snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { useState } from 'react';const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);export function SecureNestedForm() {const [profile, setProfile] = useState(() => Object.create(null));const handleDeepFieldUpdate = (keyPath, value) => {if (FORBIDDEN_KEYS.has(keyPath)) {throw new TypeError(`Restricted property assignment: ${keyPath}`);}setProfile((prev) => {const sanitizedKey = String(keyPath).trim();return Object.freeze({...prev,[sanitizedKey]: typeof value === 'string' ? value.slice(0, 100) : value});});};return (<inputaria-label="User Bio"onChange={(e) => handleDeepFieldUpdate('bio', e.target.value)}value={profile.bio || ''}/>);}
react
Breakdown
1
const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
Declares a lookup Set containing dangerous JavaScript prototype pollution access keys.
2
const [profile, setProfile] = useState(() => Object.create(null));
Initializes React state with a dictionary object that lacks a prototype chain.
3
return Object.freeze({
Immutably freezes the resulting state object to prevent downstream property mutation.