flawopen.com/Vulnerabilidades/Poluição de protótipos em JavaScript
Poluição de protótipos em JavaScript
Imagine uma oficina em que cada aparelho novo consulta um manual compartilhado quando suas próprias configurações não respondem à pergunta. Se alguém escreve uma regra controlada por um invasor nesse manual, outros aparelhos podem tratá-la como padrão. Na poluição de protótipos, gravações dinâmicas inseguras podem alterar o protótipo de um objeto, às vezes o Object.prototype. O efeito não é necessariamente global; o impacto depende de código que confie depois na propriedade herdada.
__proto__, ou um caminho constructor.prototype que alcance uma gravação inseguraMap ou dicionários sem protótipo para chaves não confiáveisConceitos principais e termos do subsistema
- Object.prototype
- Protótipo compartilhado herdado por objetos comuns. Sua poluição pode afetar muitos objetos, mas não todos os objetos JavaScript nem todos os realms.
- __proto__
- Acessor legado de objetos comuns que obtém ou define seu protótipo. Em texto JSON, a mesma grafia é apenas o nome de uma propriedade até outro código tratá-la de forma insegura.
- Mesclagem recursiva profunda
- Função que percorre chaves aninhadas e as grava em outro objeto. Torna-se perigosa quando chaves não confiáveis selecionam propriedades ligadas a protótipos ou caminhos inseguros.
- CWE-1321
- Modificação indevidamente controlada de atributos do protótipo de objetos. A falha é a mutação sem controle; o impacto posterior depende do comportamento alcançável da aplicação.
Fluxo de ataque passo a passo
Entrada de propriedades não confiáveis
Um endpoint aceita chaves de objeto controladas pelo usuário. Apenas analisar JSON com uma propriedade própria __proto__ não altera um protótipo.
Gravação dinâmica insegura
Uma mesclagem recursiva ou um setter de caminho segue essas chaves e faz gravações dinâmicas sem validar cada segmento.
Alteração do protótipo do alvo ou compartilhado
Dependendo do alvo e da sequência de gravações, a operação altera o protótipo de um alvo ou alcança um protótipo compartilhado, como Object.prototype. São resultados diferentes.
Um gadget determina o impacto
Um gadget posterior lê o valor herdado em uma operação sensível à segurança. O resultado depende desse gadget; não presuma bypass de autenticação ou execução de código.
Mecanismo e causa raiz
A busca de propriedades em JavaScript percorre a cadeia de protótipos. Uma mesclagem vulnerável ou um setter de caminho pode deixar chaves não confiáveis, como __proto__ ou constructor.prototype, direcionarem uma gravação a um protótipo. Um campo próprio __proto__ criado por JSON.parse não é, por si só, poluição; outro código precisa interpretá-lo por meio de uma atribuição insegura. Alterar o protótipo de um alvo afeta esse alvo; modificar Object.prototype afeta objetos comuns que o herdam. Um gadget separado precisa consumir a propriedade herdada para haver impacto de segurança.
// VULNERÁVEL: chaves controladas pelo invasor chegam às gravações recursivas
function merge(target, source) {
for (const key in source) {
const value = source[key];
if (value && typeof value === 'object') {
if (!target[key]) target[key] = {};
merge(target[key], value);
} else {
target[key] = value;
}
}
return target;
}
// JSON.parse cria uma propriedade própria __proto__; a mesclagem insegura é o risco.
const input = JSON.parse('{"__proto__": {"isAdmin": true}}');
merge({}, input);
// PROTEGIDO: copie apenas os campos que este endpoint aceita
const PROFILE_KEYS = new Set(['displayName', 'theme']);
function parseProfile(input) {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
throw new TypeError('profile must be an object');
}
const profile = Object.create(null);
for (const key of Object.keys(input)) {
if (!PROFILE_KEYS.has(key)) continue;
const value = input[key];
if (typeof value !== 'string' || value.length > 80) {
throw new TypeError('invalid profile field');
}
profile[key] = value;
}
return profile;
}
Sequência de ataque e exploração
- 1Entrada: uma requisição inclui uma chave de objeto inesperada, como
{"__proto__": {"admin": true}}. Analisar JSON, por si só, não altera um protótipo. - 2Gravação insegura: uma mesclagem genérica ou setter de caminho processa a chave sem uma allowlist.
- 3Acesso ao protótipo: a gravação pode alterar o protótipo do alvo ou alcançar um protótipo compartilhado, conforme o caminho do código.
- 4Gadget de impacto: a poluição só afeta uma decisão sensível se código posterior confiar numa propriedade herdada. Teste o gadget e o fluxo de autorização reais.
Engenharia defensiva e regras de prevenção
- ✓Prefira allowlists de schema: construa o destino apenas com os campos aceitos pelo endpoint. Se um gravador genérico de caminhos for inevitável, rejeite segmentos relacionados a protótipos em todos os níveis.
- ✓Use dicionários seguros: armazene chaves arbitrárias em
Mapou em um dicionárioObject.create(null); valide antes de passar os dados a APIs que esperam objetos comuns. - ✓Verifique propriedades próprias: use
Object.hasOwn(record, key)para verificações sensíveis; não permita que valores herdados autorizem ações. - ✓Use proteções do runtime como defesa em profundidade:
--disable-proto=throwdo Node.js remove um caminho, mas não bloqueiaconstructor.prototype. Congelar objetos nativos pode quebrar polyfills e dependências; avalie a compatibilidade e nunca substitua gravações seguras por essa medida.
Perguntas frequentes
Não. JSON.parse() cria uma propriedade própria chamada __proto__; não aciona o setter herdado. O risco surge se um merge ou uma atribuição posterior acionar esse setter. Veja JSON.parse() causa Prototype Pollution?
Pode impedir gravações no próprio Object.prototype congelado, mas não impede o setter de alterar o protótipo de um objeto individual nem protege todos os outros protótipos. Também pode quebrar código que estende objetos internos. Use como defesa em profundidade, não como correção do tratamento de dados.
Não. Os tipos são removidos em runtime. Um valor tipado como Record<string, string> ainda pode conter uma chave __proto__; valide chaves não confiáveis e construa objetos com segurança.
- MDN — Poluição de protótipos em JavaScript
- OWASP — Guia de prevenção de poluição de protótipos
- CWE-1321 — Modificação indevidamente controlada de atributos do protótipo de objetos
- MDN — acessor Object.prototype.__proto__