CVE-2026-17084: как str.lower() в Python стал уязвимостью безопасности
When str.lower() is a security vulnerability in Python – Seth Larson

Сет Ларсон, Security Developer-in-Residence в Python Software Foundation, объясняет, как реализация IDNA 2003 в Python оказалась уязвимой из-за использования актуальной версии Unicode вместо Unicode 3.2.0 при приведении к нижнему регистру. Это приводило к расхождению с RFC 3454 и позволяло создавать некорректные IDNA-домены. Уязвимость (CVE-2026-17084) исправлена добавлением исключений для поведения str.lower().
Вызов str.lower() в этой функции — это уязвимость!
- echoangle
Это как раз тот случай, когда вызов str.lower() представляет собой разницу между реализацией и спецификацией, и поэтому является уязвимостью:
Хотелось бы, чтобы было объяснение, чем это является уязвимостью, а не просто багом, порождающим ошибочные данные. Для меня уязвимость звучит так, будто есть разумный способ создать эксплойт из этого бага, а я его здесь не вижу, как человек, не очень знакомый с темой.
- tialaramex
Эта идиотия — большая часть того, почему было так важно, чтобы люди, работающие над реализациями TLS на Python, поняли, что определённый механизм для SAN (нет, «альтернатива» в Subject Alternative Name не означает «в смысле несколько», X.509 изначально для системы X.500, а Интернет перепрофилировал X.509, так что это альтернативные имена из Интернета) говорит, что это DNS-имена, и их ни в коем случае нельзя понимать как некий человекочитаемый текст, и поэтому их «декодирование» в Unicode — это точно бессмыслица, хотя Python очень этого хотел, и, я думаю, раньше так и делал, или по крайней мере предлагал.
Правило, как SAN DnsNames сопоставляются с подобными именами, из DNS, очень и очень простое, чтобы ты не налажал. Ты обрабатываешь один подстановочный знак (ASCII * код 42 соответствует любой отдельной DNS-метке), а в остальном это буквально сравнение байтов. Тебе не важно, что означают эти байты: либо все байты идентичны, либо это не совпадение, и всё.
- ummonk
> Исправление заключалось в создании новых исключений, чтобы str.lower() вела себя так, как если бы использовала Unicode 3.2.0 только для конкретной функции. Итак, мы проходим по каждой кодовой точке Unicode и записываем, когда поведение str.lower() отличается при сравнении версии Unicode, поставляемой с Python, и Unicode 3.2.0
Это звучит как очень хакерское решение по сравнению с реализацией отдельного замороженного lower для Unicode 3.2.0.
- jooon
Напоминает мне о старом инциденте безопасности в Spotify https://engineering.atspotify.com/2013/06/creative-usernames
- ike_sh
Столкнулся с этим однажды со знаком Кельвина. Потребовалось позорно много времени, чтобы отследить.