Contaminación de Prototipos
Bloquea los ataques de contaminación de prototipos de JSON no confiable: lodash.merge inseguro, Object.assign y los analizadores recursivos pueden envenenar cada objeto en tu proceso.
Busca en todas las páginas de la documentación
Bloquea los ataques de contaminación de prototipos de JSON no confiable: lodash.merge inseguro, Object.assign y los analizadores recursivos pueden envenenar cada objeto en tu proceso.
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
import { z } from "zod";
// Prefiere el análisis sobre la fusión para dar forma a las solicitudes
const SettingsSchema = z.object({
theme: z.enum(["light", "dark"]).optional(),
notifications: z.boolean().optional(),
});
function updateSettings(body: unknown) {
return SettingsSchema.parse(body);
}Cuándo usarlo:
_.merge, _.defaultsDeep o asignación profunda personalizada en req.body.lodash para la contaminación de prototipos.?a[b][__proto__][x]=1).import { z } from "zod";
// VULNERABLE - no hagas esto con entradas no confiables
function vulnerableMerge(target: Record<string, unknown>, source: unknown) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const _ = require("lodash");
return _.merge(target, source);
}
// SEGURO - esquema explícito, sin claves de prototipo
const PatchSchema = z.object({
displayName: z.string().min(1).max(80).optional(),
locale: z.string().regex(/^[a-z]{2}$/).optional(),
}).strict();
function safePatch(body: unknown) {
return PatchSchema.parse(body);
}
// SEGURO - asignación superficial con lista de bloqueo si debes fusionar
function safeShallowAssign<T extends Record<string, unknown>>(
target: T,
source: unknown
): T {
if (typeof source !== "object" || source === null || Array.isArray(source)) {
throw new Error("Invalid source");
}
for (const key of Object.keys(source)) {
if (["__proto__", "constructor", "prototype"].includes(key)) continue;
target[key as keyof T] = (source as Record<string, unknown>)[key] as T[keyof T];
}
return target;
}
// Demostración: el intento de ataque falla con Zod strict()
const attack = JSON.parse('{"displayName":"Ada","__proto__":{"isAdmin":true}}');
safePatch(attack); // lanza un error - clave desconocida en modo estrictoLo que esto demuestra:
_.merge copia recursivamente las claves __proto__ en los prototipos en versiones vulnerables..strict() rechaza claves desconocidas, incluyendo __proto__.JSON.parse en sí mismo está bien, el peligro es dónde asignas los datos analizados.Object.prototype.{"__proto__": {"polluted": true}} o {"constructor": {"prototype": {"polluted": true}}}.Object.prototype.polluted = true.{} pueden entonces parecer tener polluted, afectando las comprobaciones de autenticación, if (obj.isAdmin), etc.| API | Riesgo |
|---|---|
_.merge, _.defaultsDeep | CVEs históricos; evitar en JSON de usuario |
Object.assign(target, userInput) | Copia la clave __proto__ en algunos motores/rutas |
| Analizadores recursivos personalizados | Debe omitir __proto__, constructor, prototype |
Analizadores de consulta flat | qs con allowPrototypes: false |
npm ls lodash
npm auditstructuredClone de DTOs validados sobre la fusión._.mergeWith y rechaza las claves peligrosas en el personalizador.if (Object.prototype.hasOwnProperty("isAdmin")) {
throw new Error("Prototype pollution detected");
}merge(, defaultsDeep, Object.assign(req.body.req.body en la creación de Mongoose/Prisma - asignación masiva + contaminación. Solución: Analizar con Zod a DTO primero.allowPrototypes: true (predeterminado en configuraciones antiguas) - contaminación de consultas. Solución: allowPrototypes: false.additionalProperties: true - acepta __proto__. Solución: additionalProperties: false o Zod strict.__proto__ - la ruta constructor.prototype también funciona. Solución: bloquear las tres claves.| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Análisis de Zod | Formación de cuerpo/consulta HTTP | Necesidad de parche profundo de archivos de configuración anidados (usar esquema por ruta) |
| JSON Schema estricto | Rutas de Fastify | Claves arbitrarias dinámicas |
| Clon estructurado de árbol validado | Copiar objetos seguros | Antes de la validación |
| Mapa en lugar de objeto | Claves de usuario arbitrarias | La API JSON sigue usando objetos en el límite |
Sí. La vulnerabilidad es asignar valores analizados a objetos existentes a través de utilidades de fusión inseguras.
Congelar Object.prototype es posible en teoría, pero rompe muchas bibliotecas. Prefiere la validación de entrada.
JSON Schema con additionalProperties: false rechaza claves adicionales. Igual que Zod strict.
Si el código verifica if (user.isAdmin) y el atacante contamina Object.prototype.isAdmin = true, sí. Raro pero catastrófico.
Ejecuta @lavamoat/lavapack o vectores de prueba de contaminación de prototipos dedicados contra tus utilidades de fusión.
Cualquier biblioteca de establecimiento profundo en rutas no confiables es arriesgada. Permite segmentos de ruta.
Valida las variables con Zod o graphql-constraint-directive antes de que los resolvedores se fusionen en objetos.
La fusión de ramda tiene preocupaciones similares. La validación del esquema en el límite es la verdadera solución.
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activa), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.
Revisado por Chris St. John·Última actualización: 16 jul 2026