InterviewHubPRO
Section Overview
Q518

Question 518 of 521

Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

99%
JavaScript Internals (521 Qs)•Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

How do you prevent prototype pollution attacks in JavaScript?

Prototype pollution is a security vulnerability where attackers inject properties into Object.prototype, affecting all objects in the application.

Vulnerable code:

javascript
 function merge(target, source) {
   for (let key in source) {
     target[key] = source[key];
   }
   return target;
 }

 // Attack payload
 const malicious = JSON.parse('{"__proto__": {"polluted": "yes"}}');
 merge({}, malicious);

 console.log({}.polluted); // "yes" - all objects are polluted!

Prevention 1: Use Object.create(null):

javascript
 // Create objects without prototype
 const safeObj = Object.create(null);
 safeObj.__proto__ = { polluted: 'yes' };
 console.log(safeObj.polluted); // undefined

 // For configuration objects
 const config = Object.create(null);
 config.apiUrl = 'https://api.example.com';

Prevention 2: Check for dangerous keys:

javascript
 function safeMerge(target, source) {
   const dangerousKeys = ['__proto__', 'constructor', 'prototype'];

   for (let key in source) {
     if (dangerousKeys.includes(key)) {
       continue; // Skip dangerous keys
     }
     if (source.hasOwnProperty(key)) {
       target[key] = source[key];
     }
   }
   return target;
 }

Prevention 3: Use Map instead of objects:

javascript
 const safeMap = new Map();
 safeMap.set('__proto__', 'value');
 // No pollution risk

Prevention 4: Freeze Object.prototype:

javascript
 Object.freeze(Object.prototype);
 Object.freeze(Object);

 // Now pollution attempts will fail
 Object.prototype.polluted = 'no';
 console.log({}.polluted); // undefined

Prevention 5: Validate object paths:

javascript
 function setDeepProperty(obj, path, value) {
   const parts = path.split('.');
   const dangerous = ['__proto__', 'constructor', 'prototype'];

   // Validate each part of the path
   if (parts.some(part => dangerous.includes(part))) {
     throw new Error('Invalid property path');
   }

   let current = obj;
   for (let i = 0; i < parts.length - 1; i++) {
     if (!(parts[i] in current)) {
       current[parts[i]] = {};
     }
     current = current[parts[i]];
   }

   current[parts[parts.length - 1]] = value;
 }

Prevention 6: Use libraries with protection:

javascript
 // Use lodash's merge with customizer
 const _ = require('lodash');

 function safeMergeCustomizer(objValue, srcValue, key) {
   const dangerous = ['__proto__', 'constructor', 'prototype'];
   if (dangerous.includes(key)) {
     return objValue; // Keep original value
   }
 }

 const result = _.mergeWith({}, source, safeMergeCustomizer);

Prevention 7: Schema validation:

javascript
 const Ajv = require('ajv');
 const ajv = new Ajv();

 const schema = {
   type: 'object',
   properties: {
     name: { type: 'string' },
     age: { type: 'number' }
   },
   additionalProperties: false // Reject unknown properties
 };

 const validate = ajv.compile(schema);

 function safeProcess(data) {
   if (!validate(data)) {
     throw new Error('Invalid data');
   }
   return data;
 }

Prevention 8: JSON.parse with reviver:

javascript
 function safeJSONParse(text) {
   return JSON.parse(text, (key, value) => {
     const dangerous = ['__proto__', 'constructor', 'prototype'];
     if (dangerous.includes(key)) {
       return undefined; // Filter out dangerous keys
     }
     return value;
   });
 }

 const safe = safeJSONParse('{"__proto__": {"polluted": "yes"}}');
 console.log({}.polluted); // undefined