Prototype Pollution: V8 Motor İç Mekanikleri, Node.js Gadget Zincirleri ve Savunma Mimarisi

JavaScript prototip kirlenmesinin derin teknik analizi: V8 nesne modelleri, child_process ve şablon motorları üzerinden sunucu taraflı RCE zincirleri, istemci taraflı DOM vektörleri ve çalışma zamanı sertleştirme mimarileri.

13 dk okuma
ibrahimsql
2.432 kelime

Prototype Pollution: V8 Motor İç Mekanikleri, Node.js Gadget Zincirleri ve Savunma Mimarisi#

Prototip kirlenmesi (Prototype Pollution), bir JavaScript uygulamasının paylaşılan temel prototip nesnesini - çoğunlukla Object.prototype - güvenilmeyen girdiler üzerinden manipüle etmesine izin vermesi durumunda ortaya çıkar. Bu durum, saldırganın çalışma zamanındaki (runtime) neredeyse tüm JavaScript nesnelerine yeni özellikler (properties) enjekte etmesine yol açar. Geliştiriciler tarafından sıklıkla soyut bir güvenlik hatası olarak görülse de; Node.js sunucu ortamlarında veya modern istemci taraflı tek sayfa uygulamalarında (SPA), yetki yükseltme (Privilege Escalation), Hizmet Dışı Bırakma (DoS) ve Uzaktan Kod Yürütme (RCE) ile sonuçlanan kritik saldırı zincirlerine zemin hazırlar.

Bu kılavuz, prototip kirlenmesini en temelden ele alır: V8 motorunun nesne şekillerini (shapes) ve prototip zincirlerini nasıl işlediği, özyinelemeli (recursive) birleştirme algoritmalarının nasıl çöktüğü, Node.js sunucu tarafı gadget zincirlerinin (child_process, AST şablon derleyicileri) mekaniği ve mimari savunma modelleri.


1. V8 Nesne Modeli ve Prototip Kalıtımı#

ECMAScript standartlarında nesneler, anahtar-değer çiftlerinden oluşur ve dahili bir prototip işaretçisi ([[Prototype]]) barındırır. Bir nesne üzerinde bir özelliğe erişilmek istendiğinde motor, ilgili özelliğin nesnenin kendi mülkü (own property) olup olmadığını kontrol eder. Eğer özellik bulunamazsa motor, zincir boyunca yukarı doğru hareket ederek null referansına ulaşana kadar prototip zincirini tarar.

+-------------------------------------------------------------------+
|                        Örnek Nesne ({})                           |
|  - Öz Mülkler: { id: 101 }                                         |
|  - [[Prototype]] (Gizli işaretçi) -----------------------------+  |
+----------------------------------------------------------------|--+
                                                                 |
                                                                 v
+-------------------------------------------------------------------+
|                         Object.prototype                          |
|  - Standart Metotlar: toString(), valueOf(), hasOwnProperty()       |
|  - Kirletilmiş Nitelikler: { isAdmin: true, shell: "/bin/sh" }     |
|  - [[Prototype]] ----------------------------------------------+  |
+----------------------------------------------------------------|--+
                                                                 |
                                                                 v
                                                                null

1.1 __proto__ ve prototype Arasındaki Yapısal Ayrım#

  • prototype: Yalnızca yapıcı fonksiyonlarda (Object, Function, Array vb.) bulunan bir özelliktir. new anahtar kelimesiyle türetilecek nesnelerin [[Prototype]] değerinin ne olacağını tanımlar.
  • __proto__: Object.prototype üzerinde tanımlanmış bir erişimci (accessor) özelliğidir. Nesnelerin dahili [[Prototype]] işaretçisine okuma ve yazma sağlayan getter/setter fonksiyonlarını barındırır.
  • constructor: Prototip üzerinde bulunan ve nesneyi üreten yapıcı fonksiyona işaret eden referanstır (nesne.constructor.prototype === Object.prototype).
const nesne = {}; // Erişimci üzerinden doğrudan Object.prototype referansı console.log(nesne.__proto__ === Object.prototype); // true // Constructor referansı üzerinden prototipe erişim console.log(nesne.constructor.prototype === Object.prototype); // true

1.2 JSON.parse() Davranışı ve V8 Şekil (Shape) Farklılığı#

Doğrudan kod içinde tanımlanan nesne sabitleri ile JSON ayrıştırıcısı arasında kritik bir ayrım mevcuttur:

  1. Nesne Sabitleri (Object Literals): V8 motorunda { "__proto__": { "a": 1 } } ifadesi doğrudan prototip atama kuralını tetikler. Bu durumda nesnenin kendisine ait __proto__ isimli sıralanabilir (enumerable) bir anahtarı oluşmaz.
  2. JSON.parse() Ayrıştırması: ECMA-404 JSON standardı __proto__ anahtarını özel bir prototip belirleyicisi olarak tanımaz. Dolayısıyla JSON.parse('{"__proto__": {"kirletildi": true}}') çalıştırıldığında, __proto__ anahtarı nesnenin kendi mülkü (own property) olan sıradan bir nesne üretilir:
const parsed = JSON.parse('{"__proto__": {"kirletildi": true}}'); console.log(Object.prototype.hasOwnProperty.call(parsed, "__proto__")); // true console.log(Object.prototype.kirletildi); // undefined (henüz prototip zinciri bozulmadı) // Ancak bu nesne özyinelemeli bir merge işlemine girdiğinde: const hedef = {}; hedef[parsedAnahtar] = parsedDeger; // hedef['__proto__'] çağrısı Object.prototype.__proto__ setter'ını tetikler!

2. Zafiyet Vektörleri ve Hatalı Birleştirme (Merge) Motorları#

Prototip kirlenmesi pratikte üç ana yazılım deseninde oluşur: özyinelemeli nesne kopyalama/birleştirme (recursive merge/clone), derin yol (deep path) özellik atamaları ve dinamik URL/query ayrıştırmaları.

2.1 Hatalı Bir Özyinelemeli Birleştirme Fonksiyonunun Anatomisi#

Aşağıdaki savunmasız derin birleştirme fonksiyonunu inceleyelim:

function derinBirlestir(hedef, kaynak) { for (const anahtar of Object.keys(kaynak)) { if ( kaynak[anahtar] !== null && typeof kaynak[anahtar] === "object" && !Array.isArray(kaynak[anahtar]) ) { if (!hedef[anahtar]) { hedef[anahtar] = {}; } derinBirlestir(hedef[anahtar], kaynak[anahtar]); } else { hedef[anahtar] = kaynak[anahtar]; } } return hedef; }

Yürütme İzi (Execution Trace):#

  1. kaynak nesnesi {"__proto__": {"rol": "admin"}} verisini taşır.
  2. Döngü adımı: anahtar değeri "__proto__" olarak gelir.
  3. !hedef["__proto__"] kontrolü: Standart nesnelerde hedef.__proto__ zaten Object.prototype işaret ettiği için ifade false döner.
  4. Özyineleme adımı: derinBirlestir(hedef["__proto__"], kaynak["__proto__"]) çağrılır.
  5. Alt çağrıda hedef parametresi doğrudan Object.prototype adresine referans verir.
  6. İç döngü: anahtar değeri "rol" olur.
  7. Değer ataması: Object.prototype["rol"] = "admin" gerçekleştirilir.
  8. Sistem genelinde etki: Çalışma ortamında mevcut olan ve gelecekte üretilecek tüm JavaScript nesneleri artık .rol = "admin" özelliğine sahip olur.

2.2 Derin Yol Özellik Atayıcıları (Path Traversal)#

lodash.set benzeri set(obj, path, value) fonksiyonları nesne yollarını işlerken güvenli denetim yapmak zorundadır. Kullanıcı girdisi yol parametresini kontrol edebiliyorsa:

function yolAta(obj, yol, deger) { const parcalar = yol.split("."); let imlec = obj; for (let i = 0; i < parcalar.length - 1; i++) { const k = parcalar[i]; if (!imlec[k]) imlec[k] = {}; imlec = imlec[k]; } imlec[parcalar[parcalar.length - 1]] = deger; } // 1. Vektör: __proto__ erişimcisi yolAta(kullaniciAyari, "__proto__.isSuperUser", true); // 2. Vektör: constructor.prototype üzerinden dolaylı erişim yolAta(kullaniciAyari, "constructor.prototype.isSuperUser", true);

Eğer filtre mekanizması yalnızca "__proto__" kelimesini engellerse, constructor.prototype yolu filtreyi atlatır ve aynı prototip manipülasyonunu tamamlar.


3. Sunucu Taraflı (Node.js) Sömürü ve Gadget Mekanizmaları#

Object.prototype nesnesinin kirletilmesi, tüm uygulama genelinde veri sorgularını bozar. Bunun kritik bir güvenlik açığına dönüşmesi, ortamda bulunan gadget yapılarına bağlıdır. Gadget; nesnelerin kendi mülkiyeti (hasOwnProperty) olup olmadığını denetlemeden doğrudan prototipten gelen değerleri kullanan kod bloklarıdır.

+--------------------------------------------------------------------+
| 1. Enjeksiyon Vektörü                                              |
|    POST /api/profil {"__proto__": {"shell": "/bin/sh"}}            |
+---------------------------------+----------------------------------+
                                  |
                                  v
+--------------------------------------------------------------------+
| 2. Ortak Çalışma Durumu                                            |
|    Object.prototype.shell = "/bin/sh"                              |
+---------------------------------+----------------------------------+
                                  |
                                  v
+--------------------------------------------------------------------+
| 3. Gadget Tüketimi (örnek: child_process.spawn)                   |
|    child_process.fork('worker.js', [], { ... })                    |
|    Node.js dahili katmanı options.shell -> "/bin/sh" okur          |
+---------------------------------+----------------------------------+
                                  |
                                  v
+--------------------------------------------------------------------+
| 4. Uzaktan Kod Yürütme (RCE) / Güvenlik Sınırı İhlali              |
+--------------------------------------------------------------------+

3.1 Gadget 1: child_process.spawn ve fork Üzerinden RCE#

Node.js çekirdeğindeki alt süreç yönetim fonksiyonları (internal/child_process.js), süreç yapılandırması için bir options nesnesi kabul eder. Kod içerisinde spawn, execFile veya fork fonksiyonlarına aktarılan nesnede bazı alanlar açıkça belirtilmemişse, motor bu alanları prototip zincirinden okur.

Kritik Opsiyon Alanları:#

  • shell: Tanımlandığında Node.js, komutu doğrudan çalıştırmak yerine bir kabuk süreci (/bin/sh -c ... veya cmd.exe /c ...) altında sarar.
  • NODE_OPTIONS: Yeni oluşturulacak alt Node.js süreçlerine aktarılacak çevre değişkenleri.
  • env: Sürece aktarılacak ortam değişkenleri haritası.
  • argv0: Komutun 0. argümanını açıkça belirler.

Node.js Çekirdek Kaynak Kodu Analizi (lib/child_process.js):#

// Node.js child_process argüman normalizasyon mantığından alıntı function normalizeSpawnArguments(file, args, options) { options = Object.assign({}, options); let shell = options.shell; if (shell) { const command = [file].concat(args).join(' '); if (typeof shell === 'string') file = shell; else file = process.platform === 'win32' ? process.env.ComSpec : '/bin/sh'; args = ['/c', command]; } // ... }

Eğer bir arka plan görevi veya yönetim servisi shell opsiyonu vermeden spawn çağrısı yapıyorsa:

const cp = require("child_process"); // Geliştirici temiz bir opsiyon nesnesi verdiğini varsayar: const options = { timeout: 5000 }; cp.spawn("ls", ["-la"], options);

Object.prototype.shell = "/bin/bash" olarak kirletildiğinde:

  1. options.shell prototipten /bin/bash değerini alır.
  2. Node, komutu /bin/bash -c "ls -la" formatına dönüştürür.
  3. Object.prototype.argv0 veya windowsVerbatimArguments değerleri de kirletilerek yürütülecek komut ve parametreler tamamen manipüle edilebilir.

NODE_OPTIONS ile Çevre Değişkeni Enjeksiyonu:#

child_process.fork() çağrıldığında yeni bir V8 süreci ayağa kaldırılır. Sürecin ortam değişkenleri kontrol edilir:

const env = options.env || process.env;

Eğer Object.prototype.env nesnesi {"NODE_OPTIONS": "--require /tmp/malicious.js"} ile kirletilirse:

  1. options.env kirletilmiş nesneyi çözer.
  2. Yeni başlatılan Node.js alt süreci, ana betiği çalıştırmadan önce --require parametresinde belirtilen modülü belleğe yükler ve çalıştırır. Böylece doğrudan RCE elde edilir.

3.2 Gadget 2: Şablon Motoru AST Enjeksiyonu (EJS Örneği)#

Şablon motorları (Template Engines), yüksek performans elde etmek amacıyla şablonları dinamik olarak derler ve new Function() ya da eval() kullanarak çalıştırılabilir koda dönüştürür. EJS (Embedded JavaScript) geçmiş sürümlerinde prototip kirlenmesine açık kritik gadget'lar barındırmıştır.

EJS Derleyicisindeki Güvensiz Özellik Tüketimi:#

// EJS iç derleme mantığı: let opts = this.options; // Prototip zincirinden sorgulanan yapılandırma alanları: let escape = opts.escapeFunction; let client = opts.client; let outputFunctionName = opts.outputFunctionName; // Kod üretim şablonu: let src = 'var __output = "";\n' + 'with (locals || {}) {\n' + ' __output += ...\n' + '}'; if (outputFunctionName) { src = 'var ' + outputFunctionName + ' = "";\n' + src; }

Sömürü Akışı:#

  1. Saldırgan outputFunctionName alanını kirletir:
    { "__proto__": { "outputFunctionName": "x; process.mainModule.require('child_process').execSync('touch /tmp/pwned'); s" } }
  2. Uygulama normal bir şablon render işlemi gerçekleştirir: ejs.render("Merhaba <%= name %>", { name: "Ahmet" }).
  3. EJS derleyicisi kaynak kod dizesini oluşturur:
    var x; process.mainModule.require('child_process').execSync('touch /tmp/pwned'); s = ""; with (locals || {}) { ... }
  4. Derleyici new Function(src) çağrısı yaptığında enjekte edilen kabuk komutu Node.js sunucusunda anında çalıştırılır.

3.3 Gadget 3: Yetkilendirme ve Erişim Kontrolü Karışıklığı#

Modern Node.js mimarilerinde (Express, Fastify, NestJS) yetki ara yazılımları (middleware) oturum nesnesi üzerindeki rolleri kontrol eder:

function yetkiKontrol(req, res, next) { // Geliştirici kullanıcı nesnesinde boolean bayrak arar: if (req.user && req.user.isAdmin) { return next(); } return res.status(403).json({ error: "Yetkisiz Erişim" }); }

Sıradan bir kullanıcı nesnesi { id: 501, username: "ahmet" } şeklinde oluşturulmuşsa:

  1. req.user.isAdmin kendi mülkü olarak mevcut değildir.
  2. Arama prototip zincirine taşınır: Object.prototype.isAdmin.
  3. Eğer saldırgan profil güncelleme uç noktasından isAdmin: true değerini prototipe enjekte etmişse, sistemdeki tüm sıradan kullanıcılar anında yönetici (admin) yetkilerine kavuşur.

4. İstemci Taraflı (DOM) Prototip Kirlenmesi#

Tarayıcı ortamında gerçekleşen prototip kirlenmesi; Siteler Arası Betik Çalıştırma (DOM XSS) ve istemci kontrollerinin atlatılmasına zemin hazırlar.

4.1 DOM XSS Gadget Yapıları#

İstemci kütüphaneleri (analitik araçları, UI bileşenleri), harici yapılandırma nesnelerini okurken sıklıkla varsayılan değer denetimini gevşek tutar:

function eklentiYukle(ayarlar) { const script = document.createElement("script"); // URL yapılandırması kontrol edilir: script.src = ayarlar.url || "/js/default-plugin.js"; document.head.appendChild(script); }

Saldırgan URL parçası (hash) üzerinden prototipi kirletirse: https://hedef.site/#__proto__[url]=data:text/javascript,alert(document.domain)

Sayfa üzerinde eklentiYukle({}) çalıştığında:

  1. ayarlar.url prototip üzerinden data: URL değerini okur.
  2. Sayfaya kötü niyetli betik elementi dinamik olarak enjekte edilir ve çalıştırılır.

4.2 Sanitizer Konfigürasyonunun Bozulması (DOMPurify Bypass)#

HTML temizleme kütüphaneleri (örneğin DOMPurify), yapılandırma seçeneklerini bir nesne üzerinden kabul eder:

DOMPurify.sanitize(guvenilmeyenHtml, config);

Eğer config parametresi verilmezse kütüphane varsayılan kuralları nesne üzerinden çözer. Saldırgan ALLOWED_TAGS niteliğini prototipte kirletirse:

Object.prototype.ALLOWED_TAGS = ["img", "iframe", "script"];

Temizleyici, kirletilmiş etiket listesini baz alarak <script> etiketlerini filtrelemeyi bırakır ve DOM XSS açığı tetiklenir.


5. Tespit ve Davranışsal Analiz Disiplini#

Prototip kirlenmesini doğrulamak, uygulama mantığından kaynaklanan sahte pozitifleri (false positive) engellemeyi gerektirir.

5.1 Canary (Kanarya) Doğrulama Protokolü#

Doğrulama aşamasında asla uygulamada halihazırda var olabilecek (isAdmin vb.) özellikleri kullanmayın. Rastgele üretilmiş kanarya anahtarları kullanılmalıdır:

// Adım 1: Enjeksiyon yükünü gönder const payload = { "__proto__": { "__canary_test_99a": "dogrulandi" } }; // Adım 2: Bağımsız boş nesne ile sorgula const prob = {}; if (prob.__canary_test_99a === "dogrulandi") { console.error("ZAFİYET DOĞRULANDI: Object.prototype kirletildi."); }

5.2 Test Süreçlerinde Davranışsal Takip (Profiler)#

Geliştirme ve CI/CD aşamasında prototip manipülasyonlarını yakalamak için nesne tanımlayıcılarına tuzaklar (traps) yerleştirilebilir:

function prototipKorumasiBaslat() { const orjinalSetPrototypeOf = Object.setPrototypeOf; Object.setPrototypeOf = function(hedef, yeniPrototip) { console.warn("[KRİTİK UYARI] Object.setPrototypeOf tetiklendi:", hedef); return orjinalSetPrototypeOf.apply(this, arguments); }; // Temel nesnenin yeni özellik kabul etmesini engelle Object.seal(Object.prototype); }

6. Mimari Savunma ve İyileştirme (Remediation)#

Prototip kirlenmesini kalıcı olarak engellemek; girdi katmanı, veri modeli katmanı ve çalışma zamanı (runtime) katmanında çok katmanlı savunma (Defense-in-Depth) gerektirir.

+-------------------------------------------------------------------------+
|                        ÇOK KATMANLI SAVUNMA                             |
+-------------------------------------------------------------------------+
| 1. Girdi / Serileştirme Katmanı                                         |
|    - Yasaklı anahtarları filtrele: __proto__, constructor, prototype    |
|    - JSON şema doğrulaması (AJV removeAdditional: true)                 |
+------------------------------------+------------------------------------+
                                     |
                                     v
+-------------------------------------------------------------------------+
| 2. Veri Yapısı Katmanı                                                  |
|    - Sözlük yapıları için Object.create(null) kullan                    |
|    - Dinamik anahtarlar için ECMAScript Map / Set yapılarını tercih et  |
+------------------------------------+------------------------------------+
                                     |
                                     v
+-------------------------------------------------------------------------+
| 3. Çalışma Zamanı (Runtime) Katmanı                                     |
|    - Açılışta Object.freeze(Object.prototype) uygula                    |
|    - Node.js CLI bayrakları: --disable-proto=delete                     |
+-------------------------------------------------------------------------+

6.1 Güvenli Derin Birleştirme (Safe Deep Merge) Uygulaması#

Üretim ortamına uygun bir birleştirme fonksiyonu tehlikeli anahtarları ayıklamalı ve yalnızca öz mülkleri (hasOwnProperty) işlemelidir:

function guvenliDerinBirlestir(hedef, kaynak) { const YASAKLI_ANAHTARLAR = new Set(["__proto__", "constructor", "prototype"]); if (hedef === null || typeof hedef !== "object") { hedef = {}; } for (const anahtar of Object.keys(kaynak)) { if (YASAKLI_ANAHTARLAR.has(anahtar)) { continue; // Tehlikeli anahtarı doğrudan atla } if (!Object.prototype.hasOwnProperty.call(kaynak, anahtar)) { continue; } const kaynakDeger = kaynak[anahtar]; if ( kaynakDeger !== null && typeof kaynakDeger === "object" && !Array.isArray(kaynakDeger) ) { if ( !hedef[anahtar] || typeof hedef[anahtar] !== "object" || Array.isArray(hedef[anahtar]) ) { hedef[anahtar] = Object.create(null); } guvenliDerinBirlestir(hedef[anahtar], kaynakDeger); } else { hedef[anahtar] = kaynakDeger; } } return hedef; }

6.2 Prototipsiz Nesneler (Object.create(null))#

Kullanıcıdan gelen dinamik verileri anahtar-değer sözlüğü olarak tutarken sıradan {} nesneleri yerine prototipsiz nesneler tercih edilmelidir:

// Standart nesne Object.prototype'tan miras alır const zayifSozluk = {}; console.log(zayifSozluk.__proto__); // Object.prototype // Prototipsiz nesnenin prototip zinciri yoktur const guvenliSozluk = Object.create(null); console.log(guvenliSozluk.__proto__); // undefined console.log(guvenliSozluk.toString); // undefined // Güvenli sözlüğe __proto__ yazılsa dahi yukarı tırmanamaz: guvenliSozluk["__proto__"] = { admin: true }; console.log({}.admin); // undefined (Object.prototype güvendedir)

6.3 Map Veri Yapısına Geçiş#

Map yapısı kullanıcı anahtarlarını JavaScript nesne özelliklerinden tamamen yalıtır:

const kullaniciMeta = new Map(); // Güvenli saklama kullaniciMeta.set(guvenilmeyenAnahtar, guvenilmeyenDeger); // Prototip zinciri etkilenmez console.log(kullaniciMeta.get("__proto__")); console.log({}.admin); // Daima undefined

6.4 Object.prototype Nesnesini Dondurmak#

Mikroservis mimarilerinde uygulamanın giriş noktasında (bootstrap) kök prototip dondurulabilir:

// index.js dosyasının en başında: Object.freeze(Object.prototype); // Kirlenme denemesi: const obj = {}; obj.__proto__.kirlet = 123; // Strict mode altında TypeError fırlatır console.log({}.kirlet); // undefined

[!WARNING] Object.prototype dondurulduğunda, prototip üzerine polyfill veya genişletme ekleyen eski üçüncü parti kütüphaneler çalışmayabilir. Canlıya almadan önce bağımlılık uyumluluğu test edilmelidir.

6.5 Node.js Çalışma Zamanı Sertleştirme Bayrakları#

Node.js, motor seviyesinde __proto__ erişimcisini devre dışı bırakan bayraklar sunar:

# __proto__ erişiminde hata fırlatır: node --disable-proto=throw server.js # Object.prototype.__proto__ özelliğini başlangıçta tamamen siler: node --disable-proto=delete server.js

--disable-proto=delete kullanıldığında __proto__ sıradan bir nesne özelliği gibi davranır, prototip işaretçisine erişim sağlamaz. Ancak constructor.prototype zinciri için kod seviyesinde koruma devam etmelidir.


7. Savunma Stratejileri Karşılaştırma Matrisi#

StratejiPerformans EtkisiUygulama KarmaşıklığıKapsamOperasyonel Yan Etki
Anahtar Filtreleme (__proto__, constructor)İhmal EdilebilirDüşükYüksekEksik anahtar listesi veya kodlama varyantlarına karşı dikkat gerektirir.
Object.create(null) KullanımıNötr / Hızlı ErişimDüşükSözlükler için TamNesne mimarisinde bilinçli tasarım gerektirir.
Map Veri YapısıYüksek PerformansOrta (refaktör)Tam YalıtımDoğrudan JSON serileştirmesinde özel dönüştürücü gerektirir.
Object.freeze(Object.prototype)YokDüşükTüm zincirlere karşı TamPolifill kullanan eski bağımlılıkları bozabilir.
--disable-proto=deleteYokSıfır (CLI parametresi)__proto__ için Tamconstructor.prototype yolunu engellemez.

Kod İnceleme ve Denetim Kontrol Listesi#

  • Kod tabanındaki tüm merge, extend, defaultsDeep ve cloneDeep çağrılarını denetleyin.
  • İstek gövdesi ayrıştırıcılarının (body parsers) kullanıcı verilerini doğrudan dahili etki alanı modellerine kopyalamadığından emin olun.
  • child_process fonksiyonlarının (spawn, execFile, fork) tüm yürütme alanlarını (shell, env, argv0) açıkça tanımladığını doğrulayın.
  • Dinamik kullanıcı sözlüklerini {} yerine Object.create(null) veya Map ile değiştirin.
  • API uç noktalarına {"__proto__": {"canary": true}} göndererek {}.canary değerinin undefined kaldığını doğrulayan regresyon testleri ekleyin.
---
Bu yazıyı paylaş:
TwitterLinkedInFacebook

Ne düşünüyorsun?

Tepki bırakarak geri bildirim ver

İlgili Yazılar