
Skill dell'agente che analizza un codebase Rails per CVE-2026-66066 (KindaRails2Shell) — Active Storage + libvips lettura arbitraria di file / RCE, verificando le versioni di Rails e libvips e le mitigazioni block-untrusted.
Un'Agent Skill che controlla i repository Ruby on Rails per verificare l'esposizione a CVE-2026-66066 (KindaRails2Shell) — la vulnerabilità dell'elaborazione delle varianti Active Storage con libvips che consente la lettura arbitraria di file e, in un'applicazione Rails, l'esecuzione remota di codice.
La skill è uno strumento di audit della configurazione e di supporto alla remediation. Non contiene codice exploit e non descrive la catena di attacco.
| CVE | CVE-2026-66066 |
| Severity | Critica, CVSS 9.5 |
| Package | activestorage (RubyGems) |
| Affected | < 7.2.3.2, >= 8.0 < 8.0.5.1, >= 8.1 < 8.1.3.1 |
| Patched | 7.2.3.2, 8.0.5.1, 8.1.3.1 |
| Advisory | GHSA-xr9x-r78c-5hrm |
libvips legge e scrive formati tramite operazioni, alcune delle quali contrassegna come unfuzzed — non sicure per contenuti non attendibili. Active Storage non le ha disabilitate, quindi un attaccante che può caricare un file appositamente creato può raggiungerle.
Un'applicazione è esposta solo quando sono soddisfatte tutte e quattro le condizioni:
activestorage è in un intervallo di versioni interessatoconfig.active_storage.variant_processor è impostato su :vipsLa condizione 3 è quella discriminante. L'intervallo interessato < 7.2.3.2 include tutte le release di Rails 6.x, ma 6.x usa :mini_magick come impostazione predefinita, quindi 6.x è esposta solo con una configurazione non predefinita, e le release precedenti alla 6.0 non hanno affatto l'impostazione variant_processor. Rails 7.0 e successivi usano :vips come predefinito tramite config.load_defaults 7.0, motivo per cui la configurazione comune è esposta. Rails 8.1 accetta anche :disabled, il che rende falsa la condizione 3.
Come plugin di Claude Code, tramite il marketplace incluso in questo repository:
/plugin marketplace add paveg/rails-activestorage-vips-audit
/plugin install rails-activestorage-vips-audit@paveg-skills
Con la skills CLI, che installa la stessa skill in Claude Code, Codex, Cursor, Copilot CLI e altri agenti:
npx skills add paveg/rails-activestorage-vips-audit
Oppure manualmente:
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/ funziona come posizione cross-runtime per Codex, Copilot CLI e Gemini CLI. Nulla nella skill dipende da dove viene installata — non ci sono percorsi assoluti, e collect-evidence.sh risolve tutto in modo relativo alla root dell'applicazione a cui viene puntato.
La skill ha due modalità, ed entrambe accettano più percorsi di applicazioni.
report <app>... # read-only audit, one verdict per application
fix <app>... # applies remediation on a branch; never commits or pushes unprompted
Installata come plugin, ogni modalità è anche un comando, quindi la modalità non deve essere digitata come argomento:
/rails-activestorage-vips-audit:report path/to/app another/app
/rails-activestorage-vips-audit:fix path/to/app
I comandi sono punti di ingresso per te, non per l'agente: sono marcati in modo che Claude non li esegua mai da solo. Claude invoca comunque la skill stessa quando una richiesta corrisponde, motivo per cui fix non può partire senza che un essere umano lo richieda.
report è la modalità predefinita. fix richiede prima un verdetto report per la stessa applicazione, perché la remediation corretta dipende da esso — Rails 6.x, 7.0.x e 7.1.x non hanno una patch nella stessa serie, quindi fix applica la mitigazione provvisoria e segnala che è richiesto un aggiornamento del framework, invece di tentarne uno.
La raccolta delle evidenze può anche essere eseguita da sola:
skills/rails-activestorage-vips-audit/scripts/collect-evidence.sh path/to/app another/app
Lo script raccoglie fatti e non contiene deliberatamente alcuna logica di verdetto. Passa una root di applicazione, non una root di monorepo indifferenziata. Per un monorepo, passa ogni directory Rails distribuibile con il proprio Gemfile.lock e config/application.rb come argomento separato. Il collector esclude quelle root di applicazioni annidate dal flusso di evidenze del genitore, mantenendo però le root annidate con lockfile che potrebbero essere engine montati o dipendenze di percorso.
vips --version dove viene eseguita l'applicazione. I report tengono questo aspetto sotto prontezza runtime e remediation, invece di rendere condizionale il verdetto di esposizione.VIPS_BLOCK_UNTRUSTED in un Dockerfile non dimostra che l'ambiente di deploy la imposti. La skill limita tali riscontri a "mitigazione provvisoria presente, aggiornamento comunque richiesto" e non lascia mai che uno produca un verdetto pulito.Effettua l'upgrade a 7.2.3.2, 8.0.5.1 o 8.1.3.1, in base alla tua serie. Verifica prima che libvips runtime sia >= 8.13 e che ruby-vips sia >= 2.2.1: dove ruby-vips è installato, Active Storage patchato solleva un'eccezione all'avvio a meno che entrambe le condizioni siano soddisfatte, e questo controllo vale anche per le applicazioni con :mini_magick.
Mitigazioni provvisorie, nessuna delle quali sostituisce l'upgrade:
VIPS_BLOCK_UNTRUSTED (libvips >= 8.13; nessuna modifica alla gem richiesta)Vips.block_untrusted(true) da un initializer (ruby-vips >= 2.2.1, più libvips >= 8.13)Con ruby-vips < 2.2.1 la via dell'initializer chiama un metodo che non esiste ancora, quindi aggiorna prima la gem oppure segui la via della variabile d'ambiente, che non dipende da essa.
Se un'applicazione era esposta, considera compromesso ogni segreto leggibile dal processo dell'applicazione e ruotalo: secret_key_base, la master key, le credenziali del servizio Active Storage, le credenziali del database e i token di terze parti.
Un WAF non è una mitigazione in questo caso. Se possa vedere il payload dipende dal servizio di storage e dal metodo di upload, quindi la sua efficacia dipende troppo dalla configurazione per potersi affidare a esso.
La vulnerabilità è stata trovata e segnalata in modo indipendente da RyotaK di GMO Flatt Security e da un team di Ethiack composto da André Baptista, Bruno Mendes e Castilho, poi divulgata in coordinamento con i maintainer di Rails.