JSON Toolkit

Was ist __proto__-Injection

Fazit: JSON.parse behandelt __proto__ als gewöhnlichen Schlüssel; der Schaden entsteht in einem rekursiven Merge, der in Object.prototype schreibt, sodass jedes Objekt Angreifereigenschaften erbt.

Experte~5 Min. LesezeitVeröffentlicht 2026-10-30Aktualisiert 2026-10-30
Wie Prototype Pollution funktioniert und wie man sie blockiert

Kurz gesagt: Blockieren Sie __proto__, constructor und prototype vor jedem Merge, führen Sie nicht vertrauenswürdige Eingaben in Object.create(null) zusammen und ergänzen Sie eine Prototyp-Zusicherung in CI; Bibliotheken zu patchen allein genügt nicht.

In einem Satz: Ein nicht vertrauenswürdiger Schlüssel namens __proto__ trifft auf einen rekursiven Merge, und der Merge schreibt in den Prototyp.

Eine Reproduktion

function merge(target, source) {
  for (const key in source) {
    if (typeof source[key] === 'object' && source[key] !== null) {
      target[key] = target[key] || {};
      merge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}

merge({}, JSON.parse('{"__proto__": {"isAdmin": true}}'));
console.log({}.isAdmin);   // true

Kein Geschäftsobjekt wurde berührt. Object.prototype wurde es, und jedes Objekt trägt jetzt isAdmin.

Warum JSON.parse nicht schuld ist

const data = JSON.parse('{"__proto__": {"a": 1}}');
Object.getOwnPropertyNames(data);                  // [ '__proto__' ]
Object.getPrototypeOf(data) === Object.prototype;  // true, untouched

__proto__ kommt als einfache eigene Eigenschaft an. Die Gefahr liegt vollständig im Code, der später zusammenführt, tief kopiert oder nach Pfad setzt – _.merge, manche Object.assign-Muster und unzählige handgeschriebene set(obj, path, value)-Helfer.

Auswirkung

  • Autorisierungsumgehung: if (user.isAdmin) wird bedingungslos wahr
  • Datenverfälschung: unerwartete Felder serialisieren in gespeicherte Datensätze
  • Denial of Service: große Objekte am Prototyp vergrößern den Speicher dauerhaft
  • Eskalation: in Kombination mit Template-Engines oder Command-Runnern hat das zu Remote Code Execution geführt

Vier Verteidigungen

Die Schlüssel filtern.

const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);

Nur __proto__ zu blockieren genügt nicht: constructor.prototype erreicht dieselbe Stelle.

In ein Objekt ohne Prototyp zusammenführen.

const safeTarget = Object.create(null);

Ohne Prototypenkette ist __proto__ nur ein String-Schlüssel.

Object.hasOwn statt in verwenden. in konsultiert die Prototypenkette.

Abhängigkeiten gepatcht halten. lodash, deepmerge und json-patch haben alle Fixes für diese Fehlerklasse ausgeliefert. Beobachten Sie npm audit.

Prüfen, dass es behoben bleibt

Geben Sie eine Payload mit __proto__ und constructor durch Ihren Merge und prüfen Sie dann:

console.log({}.polluted);                 // undefined
console.log(Object.prototype.polluted);   // undefined

Eine Zusicherung in CI, nahezu null Kosten, fängt Regressionen aus späteren Refactorings ab.

FAQ

Welche Schlüssel sollte ein Merge herausfiltern?

Blockieren Sie __proto__, constructor und prototype gemeinsam. Nur __proto__ zu filtern genügt nicht, weil constructor.prototype denselben Prototyp erreicht.

Warum stoppt Object.create(null) den Schreibvorgang?

Ein Objekt ohne Prototyp hat keine Prototypenkette, __proto__ bleibt also ein gewöhnlicher String-Schlüssel. Es funktioniert als Datencontainer, ersetzt aber nicht die Schlüsselfilterung oder Abhängigkeitsupdates.

Wie teste ich Prototype Pollution in CI?

Senden Sie eine Payload mit __proto__ und constructor durch Ihren Merge und prüfen Sie dann, dass {}.polluted und Object.prototype.polluted undefined sind. Eine Zusicherung kostet fast nichts und fängt Regressionen aus späteren Refactorings ab.

Weiterführende Literatur