29 июля 2026 года компания Rietta в экстренном порядке применила критический патч на всей своей клиентской базе для сайтов, затронутых серьёзной уязвимостью удалённого выполнения кода в ActiveStorage — компоненте Ruby on Rails 8 и выше. Работа велась на основе GitHub Security Advisory, опубликованного в день выпуска патча. Команда исследователей Ethiack, обнаруживших уязвимость, назвала её KindaRails2Shell (CVE-2026-66066) в своём первоначальном отчёте того же дня (29 июля), с полным техническим разбором на следующий день (30 июля).
Когда команда Rietta первоначально рассмотрела эту уязвимость во время рабочего дня 29 июля, она ещё не имела присвоенного уровня серьёзности — только обновление Ruby on Rails с отложенным раскрытием деталей эксплуатации согласно стандартным условиям эмбарго. К вечеру же выяснилось, что уровень серьёзности CVSS поднялся до экстремального 9,5/10. Это означало, что любая задержка с патчированием несла риск немедленного взлома.
Характеристика клиентской базы
Клиенты Rietta включают организации, покрытые HIPAA, и государственные учреждения, многие из которых используют собственные приложения на Ruby on Rails в своей инфраструктуре. Это организации, для которых утечка данных означает существенный нормативный и репутационный ущерб, и которые не могут допустить задержки при столкновении с серьёзной угрозой.
Во время рабочего дня команда рассмотрела опубликованные детали, обнаружила, что уровень серьёзности ещё не присвоен, и первоначально квалифицировала обновление как обычное техническое обслуживание. К вечеру постоянный мониторинг показал, что CVSS вырос до 9,5/10, и была объявлена экстренная ситуация.
Патчи были применены в тот же день, когда уязвимость была объявлена и опубликована Rails security team в Possible arbitrary file read and remote code execution in Active Storage variant processing. Сам процесс был прямолинейным: команда подготовила pull requests для каждого затронутого Rails приложения, выполнив команду bundle update activestorage rails, которая загрузила последний патченный релиз. Затем команда локально запустила и позволила системе continuous integration (CI) пройти полный набор автоматических тестов. Только после успешного прохождения всех тестов, подтверждающих, что ничего не сломалось, они развернули обновление в production.
Каждый затронутый клиент был уведомлен о проведённых действиях по электронной почте. Работы были завершены около 23:30 EST.
Эмбарго на детали уже было преодолено событиями
Advisory хранил в секрете техническую цепочку атаки, обещая полное раскрытие «не позже» 28 августа 2026 года. На практике это эмбарго потеряло смысл с момента выпуска патча — не потому, что кто-то его нарушил, а потому, что сам патч, публичный code diff, никогда не был под эмбарго. Под запретом была только объяснение того, как его использовать. Но и этот запрет продержался недолго. Rails опубликовал forensic tooling со техническими деталями уже на следующий день, 30 июля в 18:25 EST, на GitHub. Ethiack опубликовал полный технический отчёт следующим утром, 31 июля в 06:56 EDT. Оба материала появились примерно за четыре недели до исходной даты эмбарго. Собственный трекинг инцидентов Rapid7 независимо подтверждает причину: Rails выпустил forensic tooling раньше графика именно потому, что несколько исследователей уже провели reverse-engineering атаки и опубликовали proof-of-concept, так что эмбарго деградировало независимо от предпочтений Rails или оригинальных исследователей.
Первая атака на клиента Rietta произошла раньше всего этого. Она состоялась в 07:10:25 EST 30 июля — через восемь часов и одну минуту после применения патча, более чем на одиннадцать часов раньше, чем собственные forensic tooling Rails стали публичны, и почти за целый день до собственного отчёта Ethiack. Первоначально предполагали, что злоумышленник самостоятельно создал payload, сравнив патч в часы после его выпуска. Новые свидетельства указывают на более простое объяснение. Public proof-of-concept эксплуит был загружен на GitHub в 21:47:30 UTC 29 июля. Это более чем за пять часов до того, как был полностью развёрнут патч Rietta (23:09 EDT 29 июля / 03:09 UTC 30 июля), и на 13 часов, 22 минуты и 55 секунд раньше первой попытки атаки на клиента.
Совпадение по времени не доказывает, что злоумышленник использовал именно этот PoC, а не что-то другое или собственное средство. Андре Баптиста из Ethiack (@0xacb), один из первооткрывателей уязвимости, указал на деталь в публичном обмене со мной в X. Этот GitHub PoC был первым публичным proof-of-concept, использовавшим повреждённый BMP файл для инициирования эксплуита. И первая попытка атаки на клиента Rietta также использовала повреждённый BMP.
Это корреляция, а не доказательство причинно-следственной связи. Но логическим выводом это простейшее объяснение, которое соответствует имеющимся свидетельствам. Это, вероятно, был не один особенно быстрый или квалифицированный злоумышленник, опередивший эмбарго. Это выглядит скорее как ecosystem исследований уязвимостей в целом, опередившей сроки скоординированного раскрытия. Даже собственный экстренный патч Rietta ещё не был готов, когда этот PoC стал публичным. Стратегия эмбарго провалилась до того, как у них была возможность закрыть эту брешь.
Баптиста сформулировал более широкую динамику ясно:
«Мы многократно воздерживались от раскрытия технических деталей, чтобы дать защитникам больше времени, но события происходят слишком быстро.»
Баптиста — один из исследователей, которые скрывали технические детали этой самой CVE, поэтому он имеет особое понимание этого вопроса.
Попытки атак начались ночью 30 июля
Один конкретный клиент, государственное учреждение, зафиксировал первую попытку атаки с повреждённым файлом Windows bitmap (BMP) 30 июля 2026 года в 07:10:25 EST с IP-адреса в сети RIPE, представившись как Chrome 131.0.0 на Windows 10. Эта первая попытка была изолированным одиночным попаданием, а не началом устойчивой активности. Логи не показывают ничего дальнейшего против этого клиента несколько дней спустя. Это соответствует зонду из раннего PoC, а не началу более широкой кампании сканирования.
Непрерывная, адаптивная волна зондирования началась отдельно 3 августа 2026 года в 01:01:05 EDT, используя замаскированный PNG файл вместо BMP из первой попытки. С этого момента попытки продолжались на ротирующемся наборе IP-адресов по всему миру, используя различные user agents, включая повреждённый спуф Anthropic's Claude-SearchBot и необычно откровенный user agent Mozilla/5.0 (CVE-2026-66066 security verification), который открыто называл CVE, на которую он зондировал, вместо того чтобы скрывать себя. Снова с международного диапазона IP-адресов.
Хотя государственный клиент Rietta и использует услуги оценки безопасности, ни одна из этих попыток — ни изолированный зонд 30 июля, ни устойчивая кампания, начавшаяся 3 августа — не приписана этим видам деятельности. Это была явно несанкционированная деятельность, и с 3 августа — постоянное зондирование этой критической уязвимости.
Попытки атак и зондирование продолжались всё август 2026 года
Попытки эксплуатации этого поведения продолжались в течение месяца ежедневно, часто в ночные часы. Есть логи, свидетельствующие о том, что фреймворки атак не только автоматизировались, но и показывают некоторые признаки адаптации — например, когда были введены определённые дополнительные меры безопасности, попытки стали использовать разные варианты. Насколько всё это было автоматизировано или какова была мотивация злоумышленников, мы в настоящее время не комментируем публично.
Временная шкала событий
| Дата и время | Событие |
|---|---|
| 21 июля 2026 | Первоначальное обнаружение законными исследователями безопасности |
| 22 июля 2026 | Исследователи связались с соответствующими разработчиками Ruby on Rails, следуя процедуре ответственного раскрытия |
| 29 июля 2026 | Выпущено критическое обновление ActiveStorage. Раскрытие и присвоение номеров отслеживания публичных уязвимостей |
| 29 июля 2026, 17:47:30 EDT | Public proof-of-concept эксплуит загружен на GitHub, за часы до завершения собственного патча |
| 29 июля 2026, PM | Поздно вечером Rietta применяет патчи на затронутых клиентов, следуя процедуре экстренного исправления |
| 29 июля 2026, 23:09 EST | Rietta развернула конкретное, протестированное обновление определённому государственному клиенту |
| 30 июля 2026, 07:10 EST | Рано утром логи исключений приложения государственного клиента указывают на первую попытку атаки с иностранного IP-адреса, изолированное одиночное попадание |
| 30 июля 2026, 20:51 EDT | Проект Ruby on Rails выпускает инструменты для проверки скомпрометирования |
| 31 июля 2026, 06:56 EDT | Андре Баптиста опубликовал технические выводы на https://ethiack.com |
| 3 августа 2026, 01:01:05 EDT | Непрерывное, устойчивое зондирование начинается с использованием замаскированного PNG файла, отличного от изолированной попытки 30 июля |
Что это означает для Rails приложений, обрабатывающих чувствительные данные
Урок здесь больше, чем просто эта CVE. Скоординированная временная шкала раскрытия не дарует защитникам льготный период. С момента выпуска патча патч сам по себе, публичный code diff, доступен любому, кто готов его прочитать вместо ожидания обычного письменного объяснения. Собственные логи доказывают, что промежуток между «патч опубликован» и «рабочий эксплуит попытался» может быть измерен часами, а не неделями, независимо от того, что говорит дата эмбарго.
Именно поэтому процедура экстренного исправления Rietta существует независимо от оценки серьёзности, первоначального общения с поставщиком или дат эмбарго. Патчируют по патчу, а не по объяснению. Для клиентов, обрабатывающих регулируемые данные — будь то HIPAA-защищённые медицинские записи или государственные системы, связанные обязательствами гласности — эта разница является смыслом сохранения отношений с фирмой, которая рассматривает «запатчено» как день один мониторинга, а не конец инцидента.
Если бы они следовали стандартному процессу уведомления и ожидания, этот клиент не получил бы рабочий патч до конца рабочего дня, вероятно, ранним утром в лучшем случае, как только кто-то с полномочиями был бы доступен для одобрения изменения. Первая попытка эксплуатации произошла в 07:10 EST, восемь часов и одну минуту после того, как они запатчили без ожидания разрешения. При обычном цикле одобрения то окно не было задержкой — это была живая, непатченная, активно целевая критическая уязвимость, открытая на всём периоде, предшествующем рабочему дню клиента, когда никто даже не был осведомлен, что требуется решение.
Все эти попытки провалились чисто, в точной точке, которую намеревался парировать патч. Но это не означает, что ничего не произошло. Месяц устойчивого, адаптивного, многоакторного зондирования против живой государственной системы — это своя история. Быстрое патчирование сделало разницу между инцидентом и не-событием. С тех пор они добавили больше усиления: более строгую валидацию загрузок, автоматическое блокирование повторных попыток сканирования и централизованные alert'ы. «Эксплуит провалился» — это результат, который они хотят продолжать получать, а не причина для ослабления внимания.
Практические рекомендации
Вот несколько практических советов для всех, особенно тех, кто не является клиентом Rietta.
- Рассматривайте любой standalone security release зависимости как срочный по умолчанию, даже до присвоения CVSS оценки. Присвоение оценки отстаёт от реального риска, иногда на много часов. Если поставщик вообще выпускает dedicated security release, не ждите числа, чтобы узнать, насколько это критично.
- Проверьте, использует ли ваше Ruby on Rails приложение ActiveStorage. Если да, и ваша команда ещё не обновилась, воспринимайте эту угрозу очень серьёзно, сразу же запатчитесь и исследуйте вашу подверженность.
- Патчируйте серьёзные уязвимости в течение часов. Заранее установите экстренный орган одобрения изменений, до того как вам это нужно, чтобы исправление не было заблокировано в ожидании того, как кто-то проснётся и даст разрешение.
- Запустите автоматизированное сканирование безопасности, специфичное для ecosystem, в качестве ежедневного задания. Для Rails это означает инструменты, такие как
bundler-audit(известные CVE в ваших зависимостях) и Brakeman (статический анализ на предмет Rails-специфичных паттернов уязвимости). По нашему опыту эти ежедневные сканы срабатывали раньше, чем собственный Dependabot GitHub, и они намного лучше, чем ожидание периодического внешнего отчёта об аудите безопасности, чтобы сказать вам, что уже была открыта. Тестируйте то, что они флагируют ежедневно. - Для любого пути кода, обрабатывающего загруженные пользователем файлы, рассматривайте его как собственную границу модели угроз. Проверяйте тип файла по magic байтам, а не по content-type заголовкам; усиливайте политику вашей библиотеки обработки изображений или документов (например, ImageMagick's
policy.xml, отключение кодеров или делегатов, которые вы не используете); и изолируйте или запускайте эту обработку с сниженными привилегиями, где сможете. Это была реальная поверхность атаки в этом инциденте. - Установите web application firewall (WAF), такой как Cloudflare или AWS WAF & Shield, мониторьте её и настройте на вашу среду. Правила на основе сигнатур часто пропускают новый payload, спрятанный внутри повреждённого файла. Рассматривайте WAF как один слой защиты, никогда весь план.
- Непрерывно добавляйте всё больше автоматизированного тестирования, чтобы дать вам уверенность, что ваше ПО работало до и после такого патчирования. Начните доверять этой сети безопасности достаточно, чтобы двигаться быстро под давлением.
- Убедитесь, что у вас есть exception monitoring на месте и что ваша техническая команда регулярно его проверяет. Неудачные запросы важны столько же, сколько успешные. Уделяйте особое внимание POST и PUT запросам к путям, которые не существуют — сильный признак adversarial зондирования. Когда что-то повторяется, добавьте валидацию и автоматизированные countermeasures, для Rails это может быть что-то вроде
rack-attackдля throttling повторных нарушителей. - Убедитесь, что ваше приложение отвечает только на запросы, направленные на ваш конкретный доменное имя, а не просто маршрутизируемые на ваш IP. Облачные провайдеры ротируют IP-адреса между клиентами, поэтому это просто хорошая гигиена и снижает шум.
- Настройте и сохраняйте логи на вашем WAF, особенно блоки, и в вашем приложении. Убедитесь, что ваше приложение регистрирует как успехи, так и сбои аутентификации, и регулярно пересматривайте.
Я знаю, что этот список может показаться объёмным. Это часто то, через что мы проводим наших клиентов и обрабатываем непосредственно от их имени. Однако это слишком важно, чтобы игнорировать. Пожалуйста, скопируйте этот список, используйте его, поделитесь с друзьями. Я хочу, чтобы вы были более безопасны, даже если мы никогда не будем работать вместе лично.