FaceHugger: RCE из-за одной f-строки в Diffusers
Библиотеку почти из каждого AI-пайплайна уронил
Zafran Labs нашли способ обойти
По второму advisory, GHSA-98h9, гейт вообще не смотрел на локальные снапшоты и custom-компоненты — та же дыра без словесной игры с None. В 0.38.0 закрыли разом: проверку перенесли в
Тянете модели с Hub через
🔗 thehackernews.com, github.com, github.com
Библиотеку почти из каждого AI-пайплайна уронил
None.Zafran Labs нашли способ обойти
trust_remote_code в Diffusers и назвали связку багов FaceHugger (пишет Hacker News, 2 августа). Самый нелепый — из advisory GHSA-j7w6: f"{custom_pipeline}.py" без аргумента превращается в "None.py", и файл с таким именем в чужом репозитории тихо выполнялся на обычном from_pretrained(repo).По второму advisory, GHSA-98h9, гейт вообще не смотрел на локальные снапшоты и custom-компоненты — та же дыра без словесной игры с None. В 0.38.0 закрыли разом: проверку перенесли в
get_cached_module_file, единственную точку, через которую идёт любая динамическая загрузка модуля.Тянете модели с Hub через
from_pretrained — гляньте pip show diffusers: если версия ниже 0.38.0, обновление не косметическое.🔗 thehackernews.com, github.com, github.com
html.parser молча уходит в O(n²)
Заголовок issue на GitHub — «Another worst case quadratic complexity in HTMLParser». Не первая такая находка в этом парсере — уже показательно.
CVE-2026-15308: скармливаешь html.parser.HTMLParser данные кусками через feed() (как все стриминговые обёртки), а внутри висит незакрытый тег или комментарий — и парсер на каждый чанк заново пересканирует весь буфер и заново его склеивает. Оба действия квадратичные. Пара мегабайт кривого HTML — и CPU в потолке без единой строчки в логе.
9 июля Serhiy Storchaka закрыл баг: буфер теперь список чанков, join и разбор — только когда данных накопилось достаточно. Патч ушёл в ветки 3.10–3.15.
Если где-то html.parser получает сеть или файл кусками — это ровно тот случай, который не поймать юнит-тестом на короткой строке.
🔗 mail.python.org, github.com, github.com
Заголовок issue на GitHub — «Another worst case quadratic complexity in HTMLParser». Не первая такая находка в этом парсере — уже показательно.
CVE-2026-15308: скармливаешь html.parser.HTMLParser данные кусками через feed() (как все стриминговые обёртки), а внутри висит незакрытый тег или комментарий — и парсер на каждый чанк заново пересканирует весь буфер и заново его склеивает. Оба действия квадратичные. Пара мегабайт кривого HTML — и CPU в потолке без единой строчки в логе.
9 июля Serhiy Storchaka закрыл баг: буфер теперь список чанков, join и разбор — только когда данных накопилось достаточно. Патч ушёл в ветки 3.10–3.15.
Если где-то html.parser получает сеть или файл кусками — это ровно тот случай, который не поймать юнит-тестом на короткой строке.
🔗 mail.python.org, github.com, github.com
FastMCP умер 28 июля — теперь это MCPServer
Если у вас MCP-сервер на FastMCP — 28 июля он перестал существовать. В буквальном смысле: класс переименовали в
Вместе с этим вышла ревизия спецификации 2026-07-28 — протокол стал полностью stateless. Раньше клиент делал handshake, получал session ID, и все следующие запросы шли через него же. Теперь хендшейка нет, ID нет — любой запрос может улететь на любой инстанс, обычный round-robin балансировщик подходит без танцев со sticky-сессиями.
По migration guide правка на одну строку:
🔗 github.com, py.sdk.modelcontextprotocol.io, blog.modelcontextprotocol.io
Если у вас MCP-сервер на FastMCP — 28 июля он перестал существовать. В буквальном смысле: класс переименовали в
MCPServer, а в блоге MCP в тот же день объяснили зачем — старый fastmcp слишком легко путали с одноимённым сторонним пакетом на своей 3.x-ветке.Вместе с этим вышла ревизия спецификации 2026-07-28 — протокол стал полностью stateless. Раньше клиент делал handshake, получал session ID, и все следующие запросы шли через него же. Теперь хендшейка нет, ID нет — любой запрос может улететь на любой инстанс, обычный round-robin балансировщик подходит без танцев со sticky-сессиями.
По migration guide правка на одну строку:
mcp.server.fastmcp меняется на mcp.server.mcpserver, FastMCP — на MCPServer, остальной код тулов не трогается. В GitHub-релизе v2.0.0 отдельно уточняют: v1.x при этом не удалили, но туда с этого дня идут только security-патчи.🔗 github.com, py.sdk.modelcontextprotocol.io, blog.modelcontextprotocol.io
Как публичный issue заставил ИИ-агента Google слить его же ключи
Нашёл историю, после которой на CI/CD с ИИ-агентами смотрю иначе.
В репозитории google/adk-python жили два бота: публичный triage-agent, который анализирует новые issue, и privileged code-fixing agent, который чинит код — но только по команде «своих».
Pillar Security затолкали в issue промпт-инъекцию. Triage-agent послушно написал
Дальше — RCE на CI-раннере и слив PAT бота,
Google убрал три воркфлоу из репы. Pillar называют это первым задокументированным agent-to-agent эксплойтом в проде. Если у вас есть бот, который реагирует на публичные issue и потом пишет команды от своего имени — это ровно ваш кейс.
🔗 pillar.security, thehackernews.com
Нашёл историю, после которой на CI/CD с ИИ-агентами смотрю иначе.
В репозитории google/adk-python жили два бота: публичный triage-agent, который анализирует новые issue, и privileged code-fixing agent, который чинит код — но только по команде «своих».
Pillar Security затолкали в issue промпт-инъекцию. Triage-agent послушно написал
/adk-issue-fix от имени adk-bot — а privileged workflow проверял только *кто* написал команду, а не подставили её или нет. adk-bot — коллаборатор, гейт пройден.Дальше — RCE на CI-раннере и слив PAT бота,
GOOGLE_API_KEY и ключа сервис-аккаунта GCP.Google убрал три воркфлоу из репы. Pillar называют это первым задокументированным agent-to-agent эксплойтом в проде. Если у вас есть бот, который реагирует на публичные issue и потом пишет команды от своего имени — это ровно ваш кейс.
🔗 pillar.security, thehackernews.com
У JIT в CPython теперь есть дедлайн — в цифрах
В июне JIT чуть не выпилили из CPython. Не за баги — за процесс: фича заехала в main через информационный PEP 744, без нормального обсуждения. Steering council дал полгода, чтобы это исправить.
Ответ — PEP 836. Не обещания, а числа по версиям. 3.15 (вот он, rc1, вышел 4 августа) — 8–9% на x86-64 Linux, 12–13% на ARM Mac. 3.16 обязан держать минимум +5%. 3.17 — уже +20%, вместе со free-threading.
Не дотянут до цифр — код уходит из main. Дедлайн на сам PEP — декабрь.
🔗 peps.python.org, blog.python.org, theregister.com
В июне JIT чуть не выпилили из CPython. Не за баги — за процесс: фича заехала в main через информационный PEP 744, без нормального обсуждения. Steering council дал полгода, чтобы это исправить.
Ответ — PEP 836. Не обещания, а числа по версиям. 3.15 (вот он, rc1, вышел 4 августа) — 8–9% на x86-64 Linux, 12–13% на ARM Mac. 3.16 обязан держать минимум +5%. 3.17 — уже +20%, вместе со free-threading.
Не дотянут до цифр — код уходит из main. Дедлайн на сам PEP — декабрь.
🔗 peps.python.org, blog.python.org, theregister.com
Один view-доступ в админке Django писал файлы на диск
Право
4 августа Django выпустил 6.0.8 и 5.2.17, закрыв разом четыре дыры. Самая злая — CVE-2026-15307:
Дальше — по драйверу: запись файла на диск или исходящий запрос прямо с сервера.
Патч режет dict и невалидные GEOSGeometry-строки прямо на входе в lookup. На прямое присваивание полю модели это не влияет — ломается только фильтрация.
Нашли баг Bence Nagy, localhost-detect и kimchunbok_.
🔗 djangoproject.com, github.com
Право
view на модель со spatial-полем в Django admin — и сервер уже пишет файл на диск. Без единого POST, просто через фильтр в changelist.4 августа Django выпустил 6.0.8 и 5.2.17, закрыв разом четыре дыры. Самая злая — CVE-2026-15307:
lookup_allowed() пропускал в spatial-lookup str и dict вместо геометрии, а GDALRaster тихо разбирал это как растр.Дальше — по драйверу: запись файла на диск или исходящий запрос прямо с сервера.
Патч режет dict и невалидные GEOSGeometry-строки прямо на входе в lookup. На прямое присваивание полю модели это не влияет — ломается только фильтрация.
Нашли баг Bence Nagy, localhost-detect и kimchunbok_.
🔗 djangoproject.com, github.com
3 тихих фикса в патч-релизе Python 3.14.7
Раз в полтора месяца выходит скучный x.y.z — обычно скроллю мимо changelog не глядя. Зря.
5 августа вышли 3.14.7 и 3.13.15, разом 499 фиксов. Из них — три, которые реально стоит знать, вынес в карточку.
Самый неприятный — base64:
И да, quadratic
🔗 github.com, github.com, github.com
Раз в полтора месяца выходит скучный x.y.z — обычно скроллю мимо changelog не глядя. Зря.
5 августа вышли 3.14.7 и 3.13.15, разом 499 фиксов. Из них — три, которые реально стоит знать, вынес в карточку.
Самый неприятный — base64:
b64decode() в обычном режиме годами молча съедал всё, что шло после первого =. RFC 4648 такого не разрешает, а код, который доверяет base64 как проверке формата, из-за этого мог пропускать лишние байты мимо себя.И да, quadratic
[1]/[last()] в xml.etree — ровно та же болезнь, что была у html.parser на прошлой неделе, просто в другом модуле.🔗 github.com, github.com, github.com
GitPython закрывал одну и ту же дыру шесть раз за три недели
Полез смотреть security advisories GitPython — и завис.
Одна причина, шестой раз подряд: kwargs с именем git-опции летят прямо в процесс
1 августа выяснилось, что сам guard
Шесть advisory за три недели на одну причину. Фикс каждый раз точечный, паттерн — нет.
🔗 github.com, advisories.gitlab.com, advisories.gitlab.com
Полез смотреть security advisories GitPython — и завис.
Одна причина, шестой раз подряд: kwargs с именем git-опции летят прямо в процесс
git, без проверки, откуда они взялись. 22 июля закрыли Repo.archive() и git.ls_remote() (CVE-2026-67323). 24-го — сразу два: clone(template=...) с исполняемыми hooks и Remote.add(), где та же утечка $ENV через URL, что чинили неделей раньше, просто с другого входа.1 августа выяснилось, что сам guard
check_unsafe_options() обходится — опцию можно спрятать внутри значения kwarg из одной буквы. 3 августа та же болезнь нашлась в checkout() и TagReference.create().Шесть advisory за три недели на одну причину. Фикс каждый раз точечный, паттерн — нет.
🔗 github.com, advisories.gitlab.com, advisories.gitlab.com
Октябрь 2026: Python 3.15 выходит — и в тот же месяц хоронит 3.10
Проверил, на чём у нас в проде крутится половина сервисов. 3.10. Ну как проверил — вспомнил после этой новости.
31 октября Python 3.10 официально уходит на пенсию: последний security-патч, дальше — только сам с собой. А 1 октября, ровно за месяц, релизится 3.15.0 (rc1 вышел 4 августа, rc2 — 1 сентября).
Один месяц, два события: новая версия въезжает, старая выезжает. Три с половиной года security-фиксов заканчиваются тихо — без анонса на весь блог, просто дата в таблице devguide.
Если у вас в CI до сих пор
🔗 python.org, devguide.python.org
Проверил, на чём у нас в проде крутится половина сервисов. 3.10. Ну как проверил — вспомнил после этой новости.
31 октября Python 3.10 официально уходит на пенсию: последний security-патч, дальше — только сам с собой. А 1 октября, ровно за месяц, релизится 3.15.0 (rc1 вышел 4 августа, rc2 — 1 сентября).
Один месяц, два события: новая версия въезжает, старая выезжает. Три с половиной года security-фиксов заканчиваются тихо — без анонса на весь блог, просто дата в таблице devguide.
Если у вас в CI до сих пор
python:3.10 — сейчас август, время есть. В декабре его уже не будет.🔗 python.org, devguide.python.org
pip 26.2: кэш индекса тихо ломает CI
У pip появилось кэширование индекса — и это тихо ломает то, что раньше работало само собой.
29 июля вышел pip 26.2: ответы индекса теперь берутся по
CI, который пушит пакет и тут же ставит его следующим шагом, поймает
Заодно:
4 августа вышел патч 26.2.1 — без изменений поведения, только баги.
🔗 discuss.python.org, sichard.ca, pip.pypa.io
У pip появилось кэширование индекса — и это тихо ломает то, что раньше работало само собой.
29 июля вышел pip 26.2: ответы индекса теперь берутся по
Cache-Control, а не ревалидируются на каждый запрос. Для PyPI это значит — только что запушенный релиз pip может не увидеть примерно 10 минут.CI, который пушит пакет и тут же ставит его следующим шагом, поймает
No matching distribution found. Обходится флагом --refresh-package.Заодно:
--only-deps — поставить зависимости пакета без него самого. --no-require-hashes — хэшированные и обычные строки уживаются в одном requirements.txt. И наконец починили build isolation на Python 3.15 — раньше она там просто не работала.4 августа вышел патч 26.2.1 — без изменений поведения, только баги.
🔗 discuss.python.org, sichard.ca, pip.pypa.io
PyPI наконец получил malware-алерты, как у npm
Наткнулся у Гитхаба на новость, которая прошла тихо: malware-алерты Dependabot почти всегда были про npm. Зловредный пакет с PyPI Advisory Database раньше обычно просто не видел, пока кто-то не заведёт CVE вручную.
7 августа GitHub рассказал, как это починили: Advisory Database тянет фид прямо из OpenSSF malicious-packages, и malware-advisories разом накрыли все восемь экосистем — npm, PyPI, Maven, RubyGems, NuGet, Go, crates.io, Composer. Включили ещё 28 июля, по changelog.
Отличие от обычного CVE: alert не ждёт ревью и CVSS — пакет попал в фид OpenSSF, и он уже в Dependabot. Настраивать ничего не надо, если малварь-алерты уже были включены.
Для меня это «наконец-то»: зловредные пакеты в PyPI раньше ловили постфактум, из твиттера security-исследователя.
🔗 github.blog, github.blog
Наткнулся у Гитхаба на новость, которая прошла тихо: malware-алерты Dependabot почти всегда были про npm. Зловредный пакет с PyPI Advisory Database раньше обычно просто не видел, пока кто-то не заведёт CVE вручную.
7 августа GitHub рассказал, как это починили: Advisory Database тянет фид прямо из OpenSSF malicious-packages, и malware-advisories разом накрыли все восемь экосистем — npm, PyPI, Maven, RubyGems, NuGet, Go, crates.io, Composer. Включили ещё 28 июля, по changelog.
Отличие от обычного CVE: alert не ждёт ревью и CVSS — пакет попал в фид OpenSSF, и он уже в Dependabot. Настраивать ничего не надо, если малварь-алерты уже были включены.
Для меня это «наконец-то»: зловредные пакеты в PyPI раньше ловили постфактум, из твиттера security-исследователя.
🔗 github.blog, github.blog
Langflow раздавал root-токен любому в интернете
Эндпоинт
Придумали это для удобства локальной разработки: не логиниться руками, а сразу получить доступ. Про то, что «локальный» и «сетевой» — не одно и то же, забыли.
Дальше
IBM закрыли дыру 2 июля, в 1.10.1. По телеметрии KEVIntel с 6 июля — уже 650 попыток атаки с 244 адресов из 41 страны. 4 августа CVE-2026-9198 (CVSS 9.8) попал в CISA KEV, федеральным агентствам дали три дня — до 7-го.
🔗 thehackernews.com, github.com, kevintel.com
Эндпоинт
/api/v1/auto_login в Langflow выдавал токен суперпользователя вообще любому, кто до него достучался — хоть с localhost, хоть с другого континента, проверки не было вовсе. Langflow — Python-конструктор LLM-агентов поверх LangChain, инструмент популярный, так что порт наружу торчит у многих.Придумали это для удобства локальной разработки: не логиниться руками, а сразу получить доступ. Про то, что «локальный» и «сетевой» — не одно и то же, забыли.
Дальше
/api/v1/validate/code берёт этот токен как доказательство, что ты свой, и гоняет присланный код через exec(). Два запроса без единого пароля — и у тебя shell с правами сервиса.IBM закрыли дыру 2 июля, в 1.10.1. По телеметрии KEVIntel с 6 июля — уже 650 попыток атаки с 244 адресов из 41 страны. 4 августа CVE-2026-9198 (CVSS 9.8) попал в CISA KEV, федеральным агентствам дали три дня — до 7-го.
🔗 thehackernews.com, github.com, kevintel.com
PEP 686: Python 3.15 переводит open() на UTF-8 везде
PEP 686 наконец добрался до релиза: с 3.15
Раньше
Откат есть:
На линуксе я разницы вообще не замечу — там и так почти всегда был UTF-8. А вот у знакомых с Windows-продакшеном это повод прогнать код с этим флагом по CI до октября, пока не выкатили финал.
Бонус: доки на docs.python.org до сих пор в паре мест пишут «encoding is locale-dependent» — issue #148603 висит открытым.
🔗 peps.python.org, docs.python.org, github.com
PEP 686 наконец добрался до релиза: с 3.15
open() по умолчанию читает и пишет в UTF-8 — везде, а не только там, где повезло с локалью.Раньше
open("f.txt").encoding на Windows мог тихо оказаться cp1252, а на Linux — utf-8. Один и тот же код, разный результат, никакого предупреждения об этом.Откат есть:
PYTHONUTF8=0 вернёт старое поведение. Но чинить лучше через -W error::EncodingWarning — он показывает каждое место, где раньше молчаливо подставлялась локаль.На линуксе я разницы вообще не замечу — там и так почти всегда был UTF-8. А вот у знакомых с Windows-продакшеном это повод прогнать код с этим флагом по CI до октября, пока не выкатили финал.
Бонус: доки на docs.python.org до сих пор в паре мест пишут «encoding is locale-dependent» — issue #148603 висит открытым.
🔗 peps.python.org, docs.python.org, github.com
Django 7.0 не выйдет — вместо неё будет 2028.0
Django выкидывает номера версий, которые все запомнили, и я не уверен, что мне это нравится.
Steering Council 10 августа принял DEP 20: вместо релиза раз в 8 месяцев — раз в год, в январе. И каждый релиз теперь живёт как раньше жили только LTS: год багфиксов, потом два года security-патчей. Ярлык «LTS» больше не нужен — так теперь у всех.
Версии переходят на CalVer. Первый релиз по новой схеме — 2028.0, в январе 2028-го. Того, что было бы Django 7.0 в декабре 2027-го, просто не будет — ждать 2028.0.
На 5.2 LTS и 6.2 LTS ничего не меняется, старые обещания по поддержке в силе.
Номер версии, из которого сразу видно год поддержки, — по мне удобнее семвера, ради которого лезешь в таблицу на djangoproject.com. Angular и Ubuntu до этого дошли раньше.
🔗 djangoproject.com, github.com
Django выкидывает номера версий, которые все запомнили, и я не уверен, что мне это нравится.
Steering Council 10 августа принял DEP 20: вместо релиза раз в 8 месяцев — раз в год, в январе. И каждый релиз теперь живёт как раньше жили только LTS: год багфиксов, потом два года security-патчей. Ярлык «LTS» больше не нужен — так теперь у всех.
Версии переходят на CalVer. Первый релиз по новой схеме — 2028.0, в январе 2028-го. Того, что было бы Django 7.0 в декабре 2027-го, просто не будет — ждать 2028.0.
На 5.2 LTS и 6.2 LTS ничего не меняется, старые обещания по поддержке в силе.
Номер версии, из которого сразу видно год поддержки, — по мне удобнее семвера, ради которого лезешь в таблицу на djangoproject.com. Angular и Ubuntu до этого дошли раньше.
🔗 djangoproject.com, github.com
PEP 831: один флаг — и perf.data легче в 55 раз
55 раз — во столько легче один и тот же perf.data, если Python собран с frame pointers вместо DWARF-unwinding. Один прогон, ~38 000 сэмплов: 5.6 МБ против 306.5 МБ на той же нагрузке.
PEP 831 переводит это в default: с 3.15 флаг
Плата — geomean 0.5–2.3% на реальных бенчмарках, у одного синтетического теста в Fedora вылезало и +9.5%. Не бесплатно, но и не повод спорить.
rc1 — 4 августа, финал 3.15.0 — 1 октября.
🔗 peps.python.org, python.org
55 раз — во столько легче один и тот же perf.data, если Python собран с frame pointers вместо DWARF-unwinding. Один прогон, ~38 000 сэмплов: 5.6 МБ против 306.5 МБ на той же нагрузке.
PEP 831 переводит это в default: с 3.15 флаг
-fno-omit-frame-pointer включён в сборке сам по себе, без плясок с пересборкой интерпретатора. perf, py-spy, eBPF-тулзы получают нормальный стек из коробки — и расширения, собранные через sysconfig, подхватывают флаг тоже.Плата — geomean 0.5–2.3% на реальных бенчмарках, у одного синтетического теста в Fedora вылезало и +9.5%. Не бесплатно, но и не повод спорить.
rc1 — 4 августа, финал 3.15.0 — 1 октября.
🔗 peps.python.org, python.org