
Навык агента для аудита кодовой базы Rails на CVE-2026-66066 (KindaRails2Shell) — произвольное чтение файлов / RCE через Active Storage + libvips, включая проверку версий Rails и libvips и митигаций block-untrusted.
Agent Skill, который проверяет репозитории Ruby on Rails на подверженность CVE-2026-66066 (KindaRails2Shell) — уязвимости обработки вариантов libvips в Active Storage, позволяющей произвольное чтение файлов и, в приложении Rails, удалённое выполнение кода.
Навык представляет собой аудитор конфигурации и средство для устранения проблемы. Он не содержит эксплойт-кода и не описывает цепочку атаки.
| CVE | CVE-2026-66066 |
| Критичность | Критическая, CVSS 9.5 |
| Пакет | activestorage (RubyGems) |
| Затронуты | < 7.2.3.2, >= 8.0 < 8.0.5.1, >= 8.1 < 8.1.3.1 |
| Исправлено | 7.2.3.2, 8.0.5.1, 8.1.3.1 |
| Рекомендация | GHSA-xr9x-r78c-5hrm |
libvips читает и записывает форматы через операции, некоторые из которых помечены как unfuzzed — небезопасные для недоверенного содержимого. Active Storage не отключал их, поэтому злоумышленник, способный загрузить специально сформированный файл, может до них добраться.
Приложение подвержено уязвимости только при выполнении всех четырёх условий:
activestorage находится в одном из затронутых диапазонов версийconfig.active_storage.variant_processor разрешается в :vipsУсловие 3 является определяющим. Затронутый диапазон < 7.2.3.2 включает все выпуски Rails 6.x, но 6.x по умолчанию использует :mini_magick, поэтому 6.x подвержен уязвимости только при нестандартной конфигурации, а в выпусках до 6.0 параметр variant_processor вообще отсутствует. Rails 7.0 и более поздние по умолчанию используют :vips через config.load_defaults 7.0, поэтому распространённая конфигурация оказывается подвержена уязвимости. Rails 8.1 также принимает :disabled, что делает условие 3 ложным.
Как плагин Claude Code через маркетплейс, включённый в этот репозиторий:
/plugin marketplace add paveg/rails-activestorage-vips-audit
/plugin install rails-activestorage-vips-audit@paveg-skills
С помощью skills CLI, который устанавливает один и тот же навык в Claude Code, Codex, Cursor, Copilot CLI и других агентов:
npx skills add paveg/rails-activestorage-vips-audit
Вручную:
git clone https://github.com/paveg/rails-activestorage-vips-audit.git
cp -r rails-activestorage-vips-audit/skills/rails-activestorage-vips-audit ~/.claude/skills/
~/.agents/skills/ работает как кросс-рантайм расположение для Codex, Copilot CLI и Gemini CLI. Ничто в навыке не зависит от места его установки — здесь нет абсолютных путей, и collect-evidence.sh разрешает всё относительно корня приложения, на который он указывает.
Навык имеет два режима, и оба принимают несколько путей к приложениям.
report <app>... # read-only audit, one verdict per application
fix <app>... # applies remediation on a branch; never commits or pushes unprompted
При установке в качестве плагина каждый режим также является командой, поэтому режим не нужно вводить как аргумент:
/rails-activestorage-vips-audit:report path/to/app another/app
/rails-activestorage-vips-audit:fix path/to/app
Команды — это точки входа для вас, а не для агента: они помечены так, чтобы Claude никогда не запускал их самостоятельно. Claude по-прежнему вызывает сам навык, когда запрос ему соответствует, поэтому fix не может запуститься без запроса от человека.
report используется по умолчанию. Для fix сначала требуется вердикт report для того же приложения, поскольку корректное исправление зависит от него — в Rails 6.x, 7.0.x и 7.1.x нет патча в той же серии, поэтому там fix применяет временную меру защиты и сообщает, что требуется обновление фреймворка, вместо попытки его выполнить.
Сбор доказательств также можно запустить отдельно:
skills/rails-activestorage-vips-audit/scripts/collect-evidence.sh path/to/app another/app
Скрипт собирает факты и намеренно не содержит логики вынесения вердикта. Передавайте корень приложения, а не недифференцированный корень монорепозитория. Для монорепозитория передавайте каждый развёртываемый каталог Rails с собственными Gemfile.lock и config/application.rb отдельным аргументом. Коллектор исключает эти вложенные корни приложений из потока доказательств родителя, сохраняя при этом вложенные корни lockfile, которые могут быть смонтированными движками или path-зависимостями.
vips --version там, где работает приложение. Отчёты относят это к готовности среды выполнения и устранению последствий, а не делают вердикт о подверженности условным.VIPS_BLOCK_UNTRUSTED в Dockerfile не доказывает, что развёрнутая среда его устанавливает. Навык ограничивает такие находки формулировкой «промежуточная мера смягчения присутствует, обновление всё ещё требуется» и никогда не позволяет им дать чистый вердикт.Обновитесь до 7.2.3.2, 8.0.5.1 или 8.1.3.1 в соответствии с вашей веткой. Сначала убедитесь, что libvips в среде выполнения >= 8.13, а ruby-vips >= 2.2.1: там, где установлен ruby-vips, исправленный Active Storage выбросит исключение при загрузке, если оба условия не выполняются, и эта проверка применима также к приложениям с :mini_magick.
Промежуточные меры смягчения, ни одна из которых не заменяет обновление:
VIPS_BLOCK_UNTRUSTED (libvips >= 8.13; изменение gem не требуется)Vips.block_untrusted(true) из инициализатора (ruby-vips >= 2.2.1, плюс libvips >= 8.13)На ruby-vips < 2.2.1 путь через инициализатор вызывает метод, которого ещё не существует, поэтому сначала обновите gem или воспользуйтесь путём через переменную окружения, который от него не зависит.
Если приложение было подвержено воздействию, считайте все секреты, доступные для чтения процессу приложения, скомпрометированными и смените их: secret_key_base, мастер-ключ, учётные данные сервиса Active Storage, учётные данные базы данных и сторонние токены.
WAF здесь не является мерой смягчения. То, может ли он увидеть полезную нагрузку, зависит от сервиса хранения и метода загрузки, поэтому его эффективность слишком зависит от конфигурации, чтобы на неё полагаться.