Уязвимость из сегодняшнего примера трудно классифицировать. Не инъекция, не BOLA, что-то совсем другое. Я бы отнесла ее к уязвимостям бизнес-логики, но она не то чтобы про логику.
Очень абстрактная подсказка: Intel когда-то упустила проблему примерно из той же области и заплатила за это 475 миллионов долларов в 95 году .
И вопрос будет не тот, который обычно задаю. Понятно, что с кодом что-то не так, если уж он в этом канале. Давайте поменяем вопрос: какой сценарий атаки?)
UPD. 100 - минимальная цена, при которой скидка применяется
Очень абстрактная подсказка: I
И вопрос будет не тот, который обычно задаю. Понятно, что с кодом что-то не так, если уж он в этом канале. Давайте поменяем вопрос: какой сценарий атаки?)
UPD. 100 - минимальная цена, при которой скидка применяется
public class DiscountService {
private static final double MIN_PRICE = 100.00;
public boolean isPromoEligible(double purchaseAmount) {
return purchaseAmount >= MIN_PRICE;
}
public double applyDiscount(double price) {
if (isPromoEligible(price)) {
return price - 10.00; // flat discount
}
return price;
}
}
Итак, разбор уязвимости этой недели - атака через точность чисел с плавающей точкой.
Как верно подметили в комментах, основная проблема этого кода -- ошибки округления, на которые все очень часто забивают. Код максимально топорный: берем сумму заказа, если она больше или равна 100, применяем скидку в 10 денежных единиц. Казалось бы, простая задача, но все же уязвимость закралась. Как же так?
А вся проблема в double. Машины хранят числа с ограниченной точностью, очевидно, и операции с плаващей точкой подчиняются стандарту IEEE 754. На скриншоте ниже приведен пример того, как эта штука работает - условно говоря, 100.00 и 99.99999999999999999997 для машины... одно и то же, если выбран неподходящий тип.
А теперь давайте представим, что речь идет о 100 и 99.99999999999999999997 долларах и о том, что эта операция может производиться, ну, к примеру, миллион раз в сутки на протяжении десятилетия. И подвержены проблеме, по сути, все языки, имеющие float и double типы. Но точно так же во всех языках настоятельно не рекомендуется применять эти типы для финансовых операций и в целом для всего, что требует высокой точности. Но есть примеры того, что использовать стоит - Java - BigDecimal, Python - Decimal, Go - big.Float - но делать это нужно явно.
Я помню, еще на курсе ассемблера в универе нам рассказывали о кейсах, когда из-за переполнений и погрешностей вычислений падали самолеты. Но найти именно ту историю не вышло, зато вот история о взрыве ракеты Ariane 5 по причине хоть и не такой же в точности, но схожей.
Как верно подметили в комментах, основная проблема этого кода -- ошибки округления, на которые все очень часто забивают. Код максимально топорный: берем сумму заказа, если она больше или равна 100, применяем скидку в 10 денежных единиц. Казалось бы, простая задача, но все же уязвимость закралась. Как же так?
А вся проблема в double. Машины хранят числа с ограниченной точностью, очевидно, и операции с плаващей точкой подчиняются стандарту IEEE 754. На скриншоте ниже приведен пример того, как эта штука работает - условно говоря, 100.00 и 99.99999999999999999997 для машины... одно и то же, если выбран неподходящий тип.
А теперь давайте представим, что речь идет о 100 и 99.99999999999999999997 долларах и о том, что эта операция может производиться, ну, к примеру, миллион раз в сутки на протяжении десятилетия. И подвержены проблеме, по сути, все языки, имеющие float и double типы. Но точно так же во всех языках настоятельно не рекомендуется применять эти типы для финансовых операций и в целом для всего, что требует высокой точности. Но есть примеры того, что использовать стоит - Java - BigDecimal, Python - Decimal, Go - big.Float - но делать это нужно явно.
Я помню, еще на курсе ассемблера в универе нам рассказывали о кейсах, когда из-за переполнений и погрешностей вычислений падали самолеты. Но найти именно ту историю не вышло, зато вот история о взрыве ракеты Ariane 5 по причине хоть и не такой же в точности, но схожей.
Owl Tutors
Computer Science: The coding error that blew up a rocket
Computer Science: The coding error that blew up a rocket - Owl Tutors
🔥4
Когда ты пентестер и выходит бага на 10.0 - это прикольно. Когда ты аппсек, думаешь - "приехали". А кто еще не видел - RCE на 10.0 в React Server Components, аффектит все, где компоненты включены.
от авторов: https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components
от wiz: https://www.wiz.io/blog/critical-vulnerability-in-react-cve-2025-55182
а ссылку на PoC публиковать не буду.
от авторов: https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components
от wiz: https://www.wiz.io/blog/critical-vulnerability-in-react-cve-2025-55182
а ссылку на PoC публиковать не буду.
react.dev
Critical Security Vulnerability in React Server Components – React
The library for web and native user interfaces
❤4👍2
Тут товарищи из хакерспейса Черный лед делают крутой ивент про путь SOC специалиста, делюсь ссылкой для всех, кто в Алматы: https://t.me/blackicehackerspace/133
Что в канале про аппсек делает ссылка на ивент про SOC? имхо, один из самых полезных на практике тандемов, если успешно работает, конечно
Что в канале про аппсек делает ссылка на ивент про SOC? имхо, один из самых полезных на практике тандемов, если успешно работает, конечно
Telegram
Чёрный Лёд
🎙️ AMA-сессия (Ask Me Anything) с практиком SOC: реальный опыт, разборы и ответы на вопросы
Tofik — специалист с практическим опытом в области информационной безопасности, работавший во внутреннем SOC, так и аутсорсинговом SOC.
💡 Обсудим всё, что касается:…
Tofik — специалист с практическим опытом в области информационной безопасности, работавший во внутреннем SOC, так и аутсорсинговом SOC.
💡 Обсудим всё, что касается:…
👍4
Сложный выдался декабрь 🙂
Но поскольку слишком больших скиллов в поздравлениях у меня нет, пришлось мое поздравление немного запрятать. И если вдруг у вас будет желание спасти, пусть не Деда Мороза, а, скажем, кого-то из его помощников, а еще будет какое-то количество свободного времени, то "подарок" для вас - в файле ниже. С наступающим!
Но поскольку слишком больших скиллов в поздравлениях у меня нет, пришлось мое поздравление немного запрятать. И если вдруг у вас будет желание спасти, пусть не Деда Мороза, а, скажем, кого-то из его помощников, а еще будет какое-то количество свободного времени, то "подарок" для вас - в файле ниже. С наступающим!
❤7🎉1
Давненько не было постов.
Когда пытаешься подобрать примеры для иллюстрации STRIDE разработчикам, всегда чуточку некомфортно с последним пунктом - повышение привилегий не по причине каких-то мисконфигураций, а именно в коде. Это всегда логическая ошибка, а с логикой сложно: ни статанализаторы ее не понимают, ни ИИ из коробки без детальной документации и объяснений. Да и примеры общеизвестные мне почему-то всегда было трудно подобрать. Спасибо ребятам из Kyverno, теперь пример будет. Да не простой, а прям сразу на CVSS 10.0.
Подробности, разбор кода(и эксплойт) доступны и детально разобраны здесь: https://github.com/advisories/GHSA-8p9x-46gm-qfx2
Что же там произошло. В Kyverno есть возможность при написании политики обратиться напрямую в Kubernetes API -
В исправлении заэнфорсили проверку того, что автор полиси не пытается посягнуть на что-то вне своего скоупа:
1. The path explicitly contains the /namespaces/<namespace>/ segment.
2. The namespace in the path matches the policy's namespace.
3. Requests missing the namespace segment (targeting cluster-scoped resources) or targeting a different namespace are rejected.
Очень нравится, как четко разобрали причину уязвимости и рассказали, как исправили. Ведь признать свои баги и прозрачно их поправить - это новое sexy.
Когда пытаешься подобрать примеры для иллюстрации STRIDE разработчикам, всегда чуточку некомфортно с последним пунктом - повышение привилегий не по причине каких-то мисконфигураций, а именно в коде. Это всегда логическая ошибка, а с логикой сложно: ни статанализаторы ее не понимают, ни ИИ из коробки без детальной документации и объяснений. Да и примеры общеизвестные мне почему-то всегда было трудно подобрать. Спасибо ребятам из Kyverno, теперь пример будет. Да не простой, а прям сразу на CVSS 10.0.
Подробности, разбор кода
Что же там произошло. В Kyverno есть возможность при написании политики обратиться напрямую в Kubernetes API -
apiCall. Проблема заключается в том, что при создании контекста, код, реализующий этот функционал, подставляет переменные напрямую в поле URLPath, не санитизируя их никаким образом и даже не проверяя, а принадлежит ли сформированный path к скоупу той полиси, которая пытается его установить. И все дальнейшие узлы, в которые эта переменная попадает, тоже не провряют именно привязки по правам, ведь дальше-то все вызовы идут от имени высокопривелигрованного Service Account Kyverno, что позволяет автору зловредной политики читать содержимое Secrets и Configmaps из других неймспейсов.В исправлении заэнфорсили проверку того, что автор полиси не пытается посягнуть на что-то вне своего скоупа:
1. The path explicitly contains the /namespaces/<namespace>/ segment.
2. The namespace in the path matches the policy's namespace.
3. Requests missing the namespace segment (targeting cluster-scoped resources) or targeting a different namespace are rejected.
Очень нравится, как четко разобрали причину уязвимости и рассказали, как исправили. Ведь признать свои баги и прозрачно их поправить - это новое sexy.
GitHub
CVE-2026-22039 - GitHub Advisory Database
Kyverno Cross-Namespace Privilege Escalation via Policy apiCall
👍10
Forwarded from Искусство. Код... ИИ?
Похоже, за n8n взялись всерьез (ну... неудивительно). Если дело так пойдет и дальше, придется заводить под их уязвимости отдельную рубрику.
Разбор упомянутых CVE в деталях можно почитать здесь, «из первых рук», так сказать. В чем суть, вкратце. Обе RCE — ответочка от jFrog на уже реализованные разработчиками n8n меры по устранению ранее обнаруженных уязвимостей, которые в итоге и привели к новым CVE-2026-1470 и CVE-2026-0863. Дело в том, что когда возможность выполнения пользователями <относительно> произвольного кода становится официальной фичей, вопрос безопасной реализации подобной функциональности слегка усложняется. Разработчики n8n пошли по пути синтаксической валидации пользовательского кода на уровне AST в обоих случаях (JavaScript, Python): код разбирается в синтаксическое дерево, дерево обходится визитором, осуществляющим детектирование потенциально опасных узлов.
И это — фиговое решение, как минимум по двум причинам.
Простых решений, здесь, увы можно не ожидать. По возрастанию
1. Если есть возможность влиять на язык, используемый для скриптов, то взять ограниченный валидацией по белым спискам (разрешенные синтаксические конструкции, пространства имен и типы) статический язык с сильной типизацией. Из известных мне языков на эту роль лучше всего подходит C# Scripting.
2. На этапе прохода по AST инструментировать код проверками на допустимость операций, которые будут осуществляться в рантайме, во время выполнения скрипта. В идеале библиотека рантайма и используемые сторонние библиотеки также должны быть инструментированы (реализацию можно подсмотреть в OpenTelemetry, например). В пределе — это приведет к разработке собственного RASP, заточенного под фичи скриптинга конкретного проекта.
3. Использовать собственноручно пропатченные интерпретаторы, допускающие только разрешенные синтаксис и семантику. Настолько сложно, что в большинстве случаев нецелесообразно.
Ну и, безотносительно способа первичной защиты: выполнять все пользовательские скрипты в изолированных контейнерах: как минимум — в Docker, как рациональный максимум — в условном FireCracker'е.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥3
как-то пропустила момент, что у Secure Code Warrior тоже есть бесплатные лабы (миссии) в рамках проекта coach. Очень нравится подход, когда виден и код, и сама страница, и дают сценарий атаки.
Вот, для примера, https://mission.securecodewarrior.com/missions/undefined/cve-2023-20860 - предлагают посмотреть, как эксплуатируется уязвимость в Spring MvcRequestMatcher
Всего доступно 8 миссий в бесплатной версии, но они хороши
Вот, для примера, https://mission.securecodewarrior.com/missions/undefined/cve-2023-20860 - предлагают посмотреть, как эксплуатируется уязвимость в Spring MvcRequestMatcher
Всего доступно 8 миссий в бесплатной версии, но они хороши
Securecodewarrior
Secure coding best practices | Secure Code Warrior
Stay up to date with secure coding best practices with our resources aimed to help you minimize the risk of software vulnerabilities creeping into your code.
👍3🔥2
уязвимость с CVSS 10.0 в pac4j-jwt , достаточно распространенной Java библиотеке для реализации аутентификацией. Ошибка очень прикольная - чек не в том месте. С кем не бывает.
полный флоу поиска, подтверждения и построения эксплойта для уязвимости доступен здесь: https://www.codeant.ai/security-research/pac4j-jwt-authentication-bypass-public-key
Классно, когда ИИ помогает сделать опенсорс безопаснее. Классно, что такие ресерчи публикуют.
полный флоу поиска, подтверждения и построения эксплойта для уязвимости доступен здесь: https://www.codeant.ai/security-research/pac4j-jwt-authentication-bypass-public-key
Классно, когда ИИ помогает сделать опенсорс безопаснее. Классно, что такие ресерчи публикуют.
codeant.ai
CVE-2026-29000: Critical Auth Bypass in pac4j-jwt: Full PoC Using Only a Public Key
CodeAnt AI found a critical authentication bypass in pac4j-jwt where an attacker can impersonate any user using only the RSA public key. Full PoC and disclosure.
🔥8
Пара объявлений
1. Классная конференция AppSecFest открыла CFP и уже доступны билеты (онлайн бесплатно, оффлайн недорого (имхо)). С каждым годом конференция все интереснее и ребята большие молодцы, поэтому вот ссылка на конфу https://appsecfest.kz/
2. В одном из чатов студенты попросили помощи в проведении опроса. Если вы студент или были им ещё недавно, поддержите ребят. Вдруг им действительно это будет полезно.
https://docs.google.com/forms/d/e/1FAIpQLSe_KCINkaTwb9ZbLISrOEBmhINjfGbPV2nytSOJHAeq_ZgzFg/viewform
1. Классная конференция AppSecFest открыла CFP и уже доступны билеты (онлайн бесплатно, оффлайн недорого (имхо)). С каждым годом конференция все интереснее и ребята большие молодцы, поэтому вот ссылка на конфу https://appsecfest.kz/
2. В одном из чатов студенты попросили помощи в проведении опроса. Если вы студент или были им ещё недавно, поддержите ребят. Вдруг им действительно это будет полезно.
https://docs.google.com/forms/d/e/1FAIpQLSe_KCINkaTwb9ZbLISrOEBmhINjfGbPV2nytSOJHAeq_ZgzFg/viewform
appsecfest.kz
AppSecFest 2026
AppSecFest — это ежегодное событие, где передовые подходы к разработке и защите приложений формируют будущее технологий.
👍4🔥1
Уязвимость с файлами в MLFlow
Декабрь 2025. Исследователь находит уязвимость в MLflow — одном из популярных инструментов для управления ML-экспериментами и деплоя моделей. Тысячи команд используют его в продакшне как часть MLOps пайплайнов. Уязвимость получает оценку CVSS в 9.1 (critical), однако патч попадает в master только через три месяца.
И вот код, который это допустил:
Давайте как всегда: что бы вы тут изменили? какая атака возможна? а разберем в пятницу
Декабрь 2025. Исследователь находит уязвимость в MLflow — одном из популярных инструментов для управления ML-экспериментами и деплоя моделей. Тысячи команд используют его в продакшне как часть MLOps пайплайнов. Уязвимость получает оценку CVSS в 9.1 (critical), однако патч попадает в master только через три месяца.
И вот код, который это допустил:
python
def extract_archive_to_dir(archive_path, dest_dir):
os.makedirs(dest_dir, exist_ok=True)
with tarfile.open(archive_path, "r") as tar:
tar.extractall(path=dest_dir)
Давайте как всегда: что бы вы тут изменили? какая атака возможна? а разберем в пятницу
не знаю, есть ли тут студенты в подписчиках, но если есть - это хороший шанс. Ребята-прикладники готовы поделиться знаниями
Forwarded from RTEAM [cybersecurity]
🎓 RTEAM запускает ежегодную летнюю стажировку
📅 10 июня — 10 июля
📍 Онлайн и офлайн — Астана, Astana Hub, блок C3.5, офис 222
Каждое лето мы открываем стажировку для тех, кто хочет зайти в кибербезопасность через практику, а не только через теорию.
Если тебе ближе Red Team или Blue Team, хочешь поработать с реальными задачами, получить наставничество и показать себя в сильной команде — подавай заявку.
Что тебя ждет:
🔹 работа рядом с практикующими специалистами
🔹 реальные задачи и процессы
🔹 шанс попасть в команду RTEAM
Чтобы подать заявку, отправь письмо на office@rteam.kz и ответь на вопросы:
Почему ты выбираешь RTEAM и что хочешь получить от стажировки?
В каком направлении ты хочешь развиваться больше — Red Team или Blue Team?
Не забудь приложить CV.
🗓️ Прием заявок — до 1 июня
Количество мест ограничено. Приглашение получат кандидаты, прошедшие отбор.
#RTEAM #Internship #Cybersecurity #RedTeam #BlueTeam #BugBounty #SOC #InfoSec #Astana #AstanaHub #Kazakhstan
📅 10 июня — 10 июля
📍 Онлайн и офлайн — Астана, Astana Hub, блок C3.5, офис 222
Каждое лето мы открываем стажировку для тех, кто хочет зайти в кибербезопасность через практику, а не только через теорию.
Если тебе ближе Red Team или Blue Team, хочешь поработать с реальными задачами, получить наставничество и показать себя в сильной команде — подавай заявку.
Что тебя ждет:
🔹 работа рядом с практикующими специалистами
🔹 реальные задачи и процессы
🔹 шанс попасть в команду RTEAM
Чтобы подать заявку, отправь письмо на office@rteam.kz и ответь на вопросы:
Почему ты выбираешь RTEAM и что хочешь получить от стажировки?
В каком направлении ты хочешь развиваться больше — Red Team или Blue Team?
Не забудь приложить CV.
🗓️ Прием заявок — до 1 июня
Количество мест ограничено. Приглашение получат кандидаты, прошедшие отбор.
#RTEAM #Internship #Cybersecurity #RedTeam #BlueTeam #BugBounty #SOC #InfoSec #Astana #AstanaHub #Kazakhstan
🔥6👍2❤1
Разбор CVE-2025-15031
В понедельник мы публиковали таск про реальную уязыимость в MLflow. Сегодня разбираем, что там произошло, почему это опасно и как это починили (три месяца чинили, кстати).
Вот уязвимый код ещё раз:
А вот ссылка на репорт: https://huntr.com/bounties/09856f77-f968-446f-a930-657d126efe4e
Проблема кроется в последней строке:
Ничто не мешает ему положить в архив файл с именем
Это атака Tar Slip — та же механика, что и Zip Slip, только для
Давайте теперь поговорим про патч. Разработчики MLflow написали отдельную функцию
1. Абсолютный путь
Файл с абсолютным путём записывается именно туда, игнорируя
2. Path traversal через `..`
Классика — выход за пределы целевой директории через
3. Traversal через симлинк
Это самый хитрый вектор. В архив кладётся симлинк
Именно поэтому в патче два прохода по членам архива: сначала собирается множество всех симлинков, потом проверяется, не ведёт ли путь файла через один из них.
И вот как выглядит исправление
И одна строка в
В контексте MLflow жертва часто даже не знает, что запускает чужой артефакт — модели регулярно обновляются и загружаются автоматически. А сам MLflow нередко работает с широкими правами, потому что ему нужен доступ к S3, базам и GPU-инфраструктуре.
Встречали ли Вы когда-нибудь похожие места в своём коде, где архивы распаковываются без проверки путей? А может, даже писали что-то подобное?🫣
В понедельник мы публиковали таск про реальную уязыимость в MLflow. Сегодня разбираем, что там произошло, почему это опасно и как это починили (три месяца чинили, кстати).
Вот уязвимый код ещё раз:
def extract_archive_to_dir(archive_path, dest_dir):
os.makedirs(dest_dir, exist_ok=True)
with tarfile.open(archive_path, "r") as tar:
tar.extractall(path=dest_dir)
А вот ссылка на репорт: https://huntr.com/bounties/09856f77-f968-446f-a930-657d126efe4e
Проблема кроется в последней строке:
tarfile.extractall() распаковывает архив, доверяя путям файлов внутри него. А эти пути — просто строки, которые записал тот, кто создавал архив, т.е. потенциальный злоумышленник.Ничто не мешает ему положить в архив файл с именем
../../config/settings.py или /etc/cron.d/backdoor. Python при распаковке честно создаст его именно там, где сказано.Это атака Tar Slip — та же механика, что и Zip Slip, только для
.tar.gz. И она в целом классическая: сама документация Python помечает extractall() как небезопасный метод начиная с 3.12. Но код был написан раньше, и никто не обратил внимания. OpenSource, hah?Давайте теперь поговорим про патч. Разработчики MLflow написали отдельную функцию
check_tarfile_security(), которая проверяет каждый файл в архиве до распаковки. Она блокирует три сценария:1. Абсолютный путь
/etc/cron.d/mlflow-backdoor
Файл с абсолютным путём записывается именно туда, игнорируя
dest_dir полностью.2. Path traversal через `..`
../../.env
../../app/config.py
Классика — выход за пределы целевой директории через
.. в имени файла.3. Traversal через симлинк
Это самый хитрый вектор. В архив кладётся симлинк
escape -> .., а потом файл escape/pwned.txt. При наивной проверке путь выглядит безобидно — никаких .. в имени. Но физически файл окажется за пределами директории назначения, потому что симлинк выводит наружу.Именно поэтому в патче два прохода по членам архива: сначала собирается множество всех симлинков, потом проверяется, не ведёт ли путь файла через один из них.
И вот как выглядит исправление
def check_tarfile_security(archive_path):
with tarfile.open(archive_path, "r") as tar:
symlink_set = set()
# Первый проход: собираем все симлинки
for m in tar.getmembers():
path = posixpath.normpath(m.name)
if m.issym():
symlink_set.add(path)
else:
# Блокируем абсолютные пути
if path.startswith("/"):
raise MlflowException(f"Absolute path is not allowed: {path}")
# Блокируем path traversal
if path.split("/")[0] == "..":
raise MlflowException(f"Escaped path is not allowed: {path}")
# Второй проход: проверяем пути через симлинки
for m in tar.getmembers():
if not m.issym():
path_parts = posixpath.normpath(m.name).split("/")
for prefix_len in range(1, len(path_parts) + 1):
prefix = "/".join(path_parts[:prefix_len])
if prefix in symlink_set:
raise MlflowException(
f"Path goes through a symlink, not allowed: {m.name}"
)
И одна строка в
extract_archive_to_dir:
def extract_archive_to_dir(archive_path, dest_dir):
check_tarfile_security(archive_path) # <- вот и весь фикс снаружи
os.makedirs(dest_dir, exist_ok=True)
with tarfile.open(archive_path, "r") as tar:
tar.extractall(path=dest_dir)
В контексте MLflow жертва часто даже не знает, что запускает чужой артефакт — модели регулярно обновляются и загружаются автоматически. А сам MLflow нередко работает с широкими правами, потому что ему нужен доступ к S3, базам и GPU-инфраструктуре.
Встречали ли Вы когда-нибудь похожие места в своём коде, где архивы распаковываются без проверки путей? А может, даже писали что-то подобное?🫣
🔥4👍2
Forwarded from Искусство. Код... ИИ?
🧩 Принципы и паттерны безопасной разработки: LSP
Часть 2.
Продолжаем разбор SOLID... на очереди — принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP). Формально он гласит: объекты подклассов должны быть способны заменить объекты базовых классов без нарушения корректности программы. Проще говоря, наследник не должен «ломать» контракт, установленный родителем — ни в предусловиях (не требовать большего), ни в постусловиях (не гарантировать меньшего), ни в инвариантах (не нарушать постоянных условий).
Что неочевидно для многих, благодаря дядюшке Мартину, так это то, что LSP является поведенческим принципом, а не структурным. Иными словами, чтобы нарушить его, наследование (да и ООП в целом) — вообще не нужно. Если у нас есть одна сущность, переопределяющая поведение другой, и при этом к ней можно обратиться, как к исходной — этого достаточно. Даже, если сущности — результат функциональной композиции, без каких-либо объектов в терминах ООП в целом. Пример того, как LSP выглядит в языках, не имеющих наследования, можно посмотреть тут.
С точки зрения безопасности, нарушение LSP — это прямая дорога к обходу защитных механизмов. Когда подкласс изменяет семантику безопасности базового класса (например, отключает проверку прав доступа или меняет логику валидации), код, написанный с расчётом на родительский контракт, начинает работать непредсказуемо. Это порождает логические уязвимости, которые сложно отловить статическим анализом, поскольку формально типы совместимы, а вот их поведение — нет.
Как правило, нарушения LSP могут повлечь за собой примерно любые уязвимости, так или иначе связанные с логикой работы приложения. «В природе», однако, чаще всего они относятся ко следующим категориям:
• CWE-264: Permissions, Privileges, and Access Controls
• CWE-284: Improper Access Control
• CWE-290: Authentication Bypass by Spoofing
• CWE-703: Improper Check or Handling of Exceptional Conditions
🐛 Жизненное
CVE-2025-22223 — Spring Security (Authentication Bypass by Spoofing).
Когда аннотация безопасности (
Нарушение LSP здесь в том, что родительский тип объявляет контракт «этот метод требует роли ADMIN». Подкласс переопределяет метод, и контракт безопасности молча пропадает. При подстановке подкласса вместо родителя предусловие (авторизация) ослабляется.
Патч (коммит dc2e1af). Наивный поиск
❗️ Что делать?
• Помечайте security-critical классы как
• Аннотации безопасности дублируйте на каждом переопределяющем методе.
• Фильтруйте и определяйте сущности по их типу, а не по имени.
• Соблюдайте явным образом все поведенческие контракты переопределяемых методов.
• Обеспечивайте инварианты объекта даже при аварийном завершении конструктора или инициализации.
⚠ TL;DR: В целом, общий принцип один: если ваш код принимает сущность по ссылке на базовую реализацию, он неявно доверяет поведенческому контракту этой сущности. Убедитесь, что это обосновано — особенно на границах доверия между компонентами системы.
Часть 2.
Продолжаем разбор SOLID... на очереди — принцип подстановки Барбары Лисков (Liskov Substitution Principle, LSP). Формально он гласит: объекты подклассов должны быть способны заменить объекты базовых классов без нарушения корректности программы. Проще говоря, наследник не должен «ломать» контракт, установленный родителем — ни в предусловиях (не требовать большего), ни в постусловиях (не гарантировать меньшего), ни в инвариантах (не нарушать постоянных условий).
Что неочевидно для многих, благодаря дядюшке Мартину, так это то, что LSP является поведенческим принципом, а не структурным. Иными словами, чтобы нарушить его, наследование (да и ООП в целом) — вообще не нужно. Если у нас есть одна сущность, переопределяющая поведение другой, и при этом к ней можно обратиться, как к исходной — этого достаточно. Даже, если сущности — результат функциональной композиции, без каких-либо объектов в терминах ООП в целом. Пример того, как LSP выглядит в языках, не имеющих наследования, можно посмотреть тут.
С точки зрения безопасности, нарушение LSP — это прямая дорога к обходу защитных механизмов. Когда подкласс изменяет семантику безопасности базового класса (например, отключает проверку прав доступа или меняет логику валидации), код, написанный с расчётом на родительский контракт, начинает работать непредсказуемо. Это порождает логические уязвимости, которые сложно отловить статическим анализом, поскольку формально типы совместимы, а вот их поведение — нет.
Как правило, нарушения LSP могут повлечь за собой примерно любые уязвимости, так или иначе связанные с логикой работы приложения. «В природе», однако, чаще всего они относятся ко следующим категориям:
• CWE-264: Permissions, Privileges, and Access Controls
• CWE-284: Improper Access Control
• CWE-290: Authentication Bypass by Spoofing
• CWE-703: Improper Check or Handling of Exceptional Conditions
🐛 Жизненное
CVE-2025-22223 — Spring Security (Authentication Bypass by Spoofing).
Когда аннотация безопасности (
@PreAuthorize) размещена на методе обобщённого суперкласса или интерфейса, и конкретный подкласс переопределяет этот метод, механизм UniqueSecurityAnnotationScanner не находит аннотацию на переопределённом методе. Причина -- использование targetClass.getDeclaredMethod(method.getName(), method.getParameterTypes()) для поиска, что не работает после стирания типов (type erasure): сигнатура родительского метода Object mutate(Object) не совпадает с сигнатурой конкретной реализации AccountSecret mutate(AccountSecret).public abstract class BaseService<T> {
@PreAuthorize("hasRole('ADMIN')")
public abstract T getResource(Long id);
}
// Подкласс -- Spring Security не видит аннотацию
public class UserService extends BaseService<User> {
@Override
public User getResource(Long id) {
return userRepo.findById(id);
}
}Нарушение LSP здесь в том, что родительский тип объявляет контракт «этот метод требует роли ADMIN». Подкласс переопределяет метод, и контракт безопасности молча пропадает. При подстановке подкласса вместо родителя предусловие (авторизация) ослабляется.
Патч (коммит dc2e1af). Наивный поиск
getDeclaredMethod заменен на итерацию по всем методам класса с разрешением обобщённых типов.• Помечайте security-critical классы как
final|sealed или явно контролируйте наследование.• Аннотации безопасности дублируйте на каждом переопределяющем методе.
• Фильтруйте и определяйте сущности по их типу, а не по имени.
• Соблюдайте явным образом все поведенческие контракты переопределяемых методов.
• Обеспечивайте инварианты объекта даже при аварийном завершении конструктора или инициализации.
Please open Telegram to view this post
VIEW IN TELEGRAM
2087 год, исследовательская станция на дневной стороне Меркурия.
Жара была просто изматывающей: за куполом - 430°C, месяцами без захода Солнца. Автоматика охлаждения держала +28 внутри, а до длинной меркурианской ночи оставалось еще почти 30 земных суток. Команда работала на пределе, до наступления Меркурианской Ночи необходимо было запустить пассажирский портал Меркурий-Юпитер, или просто Портал, если коротко. Каждые семь часов через купол уходит группа в сторону Юпитера, и Портал реализует весь программный контроль. Безопасность держится на одной штуке: у каждого пассажира на личном устройстве установлено приложение, которое перед проходом подтверждает личность токеном с коротким сроком жизни.
В команде Кая четверо разработчиков. Они живот под Куполом уже два месяца, они прилетели Ночью, а до конца смены нужно пережить длинный, жаркий, изматывающий День. Спят плохо, работают медленно, голова к вечеру ватная. Но у каждого - свой персональный Оракул и, будем честны, во многом именно благодаря ему в этих условиях проект вообще хоть как-то движется. Оракул - это не просто LLM, скорее компаньон, обученный на всем коде, который был написан за прошедшие сто лет, но также и на всех CVE и всех патчах.
Утро Кая началось как всегда: с холодного кофе. Привычка пить кофе со льдом, который на Земле казался ему таким странным, появилась у него за пять лет жизни на Станции. Открыв код метода аутентификации, он вспомнил, что давно собирался отрефакторить его, убрав варианты, которые так и не дошли до итоговой версии Портала.
- Перепиши проверку токена. Хочу почище. - сказал Кай Оракулу.
Оракул ответил как всегда в последние двадцать лет: мгновенно. Кай посмотрел на diff. "Красиво, однако, пишет. Как же давно я не писал код сам. Кажется, он справляется лучше меня: меньше строк, читаемее. А, к черту, он еще не подводил". Кай нажимает Approve. На сегодня всё, голова не варит.
Чем хуже справляется охлаждение, тем больше Кай полагается на Оракула, он давно это заметил. Да и в команде, судя по всему, все устроено так же: нужно просто дотянуть смену и вернуться на Землю. Правда, переброской через Юпитер. Через их же собственный Портал. Как же задолбала эта жара.
На сорок третий день Каю позвонили из центра реагирования: что-то странное со шлюзом аутентификации, похоже, Чужому удалось пробраться через Портал во время его тестирования. По поднятым логам Кай видит, что Чужой действительно прошел через Портал еще две недели назад, а ведь проект все еще даже не запущен официально. Расследование занимает шесть часов, и тут тоже помогает Оракул: он быстро анализирует всю доступную информацию и показывает тот самый коммит. Код действительно стал чище. Только в нём пропала проверка expiration, просто пропала. Не заметил никто - потому что кто читает diff в +34 в каюте на исходе смены.
Кай не злится на Оракула, ведь он не обманывал, не делал ничего злонамеренного. Кай злится на себя - за то, что перестал читать.
Жара была просто изматывающей: за куполом - 430°C, месяцами без захода Солнца. Автоматика охлаждения держала +28 внутри, а до длинной меркурианской ночи оставалось еще почти 30 земных суток. Команда работала на пределе, до наступления Меркурианской Ночи необходимо было запустить пассажирский портал Меркурий-Юпитер, или просто Портал, если коротко. Каждые семь часов через купол уходит группа в сторону Юпитера, и Портал реализует весь программный контроль. Безопасность держится на одной штуке: у каждого пассажира на личном устройстве установлено приложение, которое перед проходом подтверждает личность токеном с коротким сроком жизни.
В команде Кая четверо разработчиков. Они живот под Куполом уже два месяца, они прилетели Ночью, а до конца смены нужно пережить длинный, жаркий, изматывающий День. Спят плохо, работают медленно, голова к вечеру ватная. Но у каждого - свой персональный Оракул и, будем честны, во многом именно благодаря ему в этих условиях проект вообще хоть как-то движется. Оракул - это не просто LLM, скорее компаньон, обученный на всем коде, который был написан за прошедшие сто лет, но также и на всех CVE и всех патчах.
Утро Кая началось как всегда: с холодного кофе. Привычка пить кофе со льдом, который на Земле казался ему таким странным, появилась у него за пять лет жизни на Станции. Открыв код метода аутентификации, он вспомнил, что давно собирался отрефакторить его, убрав варианты, которые так и не дошли до итоговой версии Портала.
- Перепиши проверку токена. Хочу почище. - сказал Кай Оракулу.
Оракул ответил как всегда в последние двадцать лет: мгновенно. Кай посмотрел на diff. "Красиво, однако, пишет. Как же давно я не писал код сам. Кажется, он справляется лучше меня: меньше строк, читаемее. А, к черту, он еще не подводил". Кай нажимает Approve. На сегодня всё, голова не варит.
Чем хуже справляется охлаждение, тем больше Кай полагается на Оракула, он давно это заметил. Да и в команде, судя по всему, все устроено так же: нужно просто дотянуть смену и вернуться на Землю. Правда, переброской через Юпитер. Через их же собственный Портал. Как же задолбала эта жара.
На сорок третий день Каю позвонили из центра реагирования: что-то странное со шлюзом аутентификации, похоже, Чужому удалось пробраться через Портал во время его тестирования. По поднятым логам Кай видит, что Чужой действительно прошел через Портал еще две недели назад, а ведь проект все еще даже не запущен официально. Расследование занимает шесть часов, и тут тоже помогает Оракул: он быстро анализирует всю доступную информацию и показывает тот самый коммит. Код действительно стал чище. Только в нём пропала проверка expiration, просто пропала. Не заметил никто - потому что кто читает diff в +34 в каюте на исходе смены.
Кай не злится на Оракула, ведь он не обманывал, не делал ничего злонамеренного. Кай злится на себя - за то, что перестал читать.
🔥2😁1
просто интересная статья от лида разработки curl про Mythos и в целом мысли о том, что не использовать AI агенты для анализа кода на безопасность - уже глупо, но пугаться от каждой новости про невероятные возможности новой модели - наверное, тоже не очень правильно. Подтверждает то же, что раньше говорили в исследовании aisle, что в целом, важна не столько крутая модель, сколько правильно выстроенная архитектура ее использования.
https://daniel.haxx.se/blog/2026/05/11/mythos-finds-a-curl-vulnerability/
https://daniel.haxx.se/blog/2026/05/11/mythos-finds-a-curl-vulnerability/
daniel.haxx.se
Mythos finds a curl vulnerability
yes, as in singular one. Back in April 2026 Anthropic caused a lot of media noise when they concluded that their new AI model Mythos is dangerously good at finding security flaws in source code. Apparently Mythos was so good at this that Anthropic would not…
👍5