Overheidswebsite op Rails aangevallen uren na CVE-patch

De kwetsbaarheid en de reactie

Na kantoortijden op woensdag 29 juli 2026 voerde Rietta de noodprocedure voor hotfixes uit voor alle klanten wiens sites waren getroffen door een ernstige kwetsbaarheid voor remote code execution (RCE) in ActiveStorage, een component van Ruby on Rails 8 en nieuwer. We baseerden ons op de initiële GitHub Security Advisory, die op dezelfde dag als de patch werd gepubliceerd. Ethiack, een van de onderzoeksteams die de fout ontdekte, noemde de kwetsbaarheid KindaRails2Shell (CVE-2026-66066) in hun eerste openbaarmaking op 29 juli; een volledige technische analyse volgde de volgende dag, 30 juli.

Toen ons team deze kwetsbaarheid tijdens kantooruren op de 29e voor het eerst bekeek, was er nog geen ernst (severity) aan toegekend. Er was enkel een update voor Ruby on Rails uitgebracht, waarbij de details over de exploitatie werden geheimgehouden onder de standaard embargo-voorwaarden. Tegen de avond zag ons team echter dat de score was gestegen naar een extreem ernstige CVSS-score van 9.5/10. Dit is ongeveer het ergste dat kan gebeuren en betekende dat elke vertraging in het patchen een existentieel risico op onmiddellijke compromittering vormde.

Achtergrond van de client

Onze klantenkring omvat entiteiten die onder HIPAA vallen en overheidsinstanties van staten, van wie velen maatwerkapplicaties op basis van Ruby on Rails binnen hun infrastructuur hebben. Dit zijn organisaties die bij een datalek te maken krijgen met aanzienlijke reglementaire en reputatieschade, en zij kunnen zich geen vertraging veroorloven bij een ernstige dreiging.

Tijdens kantooruren beoordeelde ons team de gepubliceerde details. Omdat er nog geen ernst was toegewezen, werd het aanvankelijk gecategoriseerd als een reguliere update die binnen de normale onderhoudsvensters kon worden uitgevoerd. Tegen de avond toonde onze continue monitoring aan dat de CVSS-score was gestegen naar 9.5/10, waarna we een noodsituatie voor de hotfix uitriepen.

Deze patches werden toegepast op dezelfde dag dat de kwetsbaarheid werd aangekondigd en gepubliceerd door het Rails-beveiligingsteam in "Possible arbitrary file read and remote code execution in Active Storage variant processing". Het proces zelf was rechttoe rechtaan: het team bereidde pull-requests voor voor elke getroffen Rails-app met het commando bundle update activestorage rails, waarmee de nieuwste gepatchte release werd opgehaald. Vervolgens voerde het team lokaal en via continuous integration (CI) de volledige geautomatiseerde testsuite uit. Pas nadat de volledige testsuites zonder fouten waren doorlopen — wat bevestigde dat er niets anders kapot was gegaan — implementeerden we de patch in productie.

We hebben elke getroffen klant via e-mail op de hoogte gesteld van deze actie en het werk rond 23:30 uur EST afgerond.

Het embargo werd ingehaald door de gebeurtenissen

De waarschuwing hield het technische scenario van de aanval geheim en beloofde volledige openbaarmaking "uiterlijk" op 28 augustus 2026. In de praktijk was dat embargo functioneel betekenisloos vanaf het moment dat de patch werd verzonden, niet omdat iemand het embargo verbrak, maar omdat de fix zelf — een publieke code diff — nooit onder embargo stond, enkel de uitleg over hoe deze te exploiteren.

Die uitleg hield niet eens een maand stand. Het Rails-project publiceerde de volgende dag, op 30 juli om 18:25 uur EST, forensische tooling met technische details op GitHub. Ethiack publiceerde de volgende ochtend, 31 juli om 06:56 uur EDT, het volledige technische verslag. Beiden verschenen ongeveer vier weken vóór de oorspronkelijk gestelde embargo-datum in de GitHub Advisory. Incidenttracking van Rapid7 bevestigt onafhankelijk waarom dit gebeurde: Rails bracht de forensische tooling eerder uit dan gepland, specifiek omdat verschillende onderzoekers de aanval al hadden gereverse-engineered en proof-of-concept (PoC) code hadden gepubliceerd. Het embargo week dus sowieso, ongeacht de voorkeur van Rails of de oorspronkelijke onderzoekers.

De eerste aanval op onze klant vond plaats vóór al deze gebeurtenissen. Deze vond plaats op 30 juli om 07:10:25 uur EST, acht uur en één minuut nadat wij de patch hadden toegepast, meer dan elf uur voordat de forensische tooling van Rails openbaar werd en bijna een volle dag voordat het verslag van Ethiack verscheen. Aanvankelijk namen we aan dat wie deze eerste payload had gebouwd, dit onafhankelijk had gedaan door zelf de fix te analyseren via patch-diffing in de uren na publicatie. Nieuw bewijs wijst echter op een eenvoudigere verklaring: een publieke PoC-exploit werd op 29 juli om 21:47:30 uur UTC naar GitHub gepusht. Dat is meer dan 5 uur voordat onze eigen patch volledig was geïmplementeerd (23:09 uur EDT / 03:09 uur UTC op 30 juli), en 13 uur, 22 minuten en 55 seconden voordat de eerste aanvalspoging op onze klant plaatsvond.

Timing alleen bewijst niet dat onze aanvaller specifiek die PoC gebruikte. André Baptista van Ethiack (@0xacb), een van de ontdekkers van de kwetsbaarheid, wees in een publieke uitwisseling op X op een detail: die GitHub PoC was de eerste publieke proof-of-concept die een misvormd BMP-bestand gebruikte om de exploit te triggeren. De eerste aanvalspoging op onze klant maakte eveneens gebruik van een kwaadaardig gevormd BMP-bestand.

Hoewel dit een correlatie is en geen bewijs van causaliteit, is het via logische abductie de simpelste verklaring die past bij het bewijs. Dit was waarschijnlijk geen uitzonderlijk snelle of bekwame aanvaller die in zijn eentje het embargo versloeg. Het lijkt er eerder op dat het ecosysteem van kwetsbaarheidsonderzoek als geheel sneller ging dan de gecoördineerde tijdlijn voor openbaarmaking. Onze eigen noodpatch was nog niet eens klaar toen die PoC openbaar werd. De embargo-strategie faalde voordat we de kans hadden om het gat te dichten.

Baptista verwoordde de bredere dynamiek helder: "We hebben in meerdere gevallen technische details achtergehouden om verdedigers meer tijd te geven, maar de dingen gaan simpelweg te snel."

Aanvalspogingen startten in de nacht van 30 juli

Eén specifieke client, een overheidsinstantie van een staat, logde de eerste aanvalspoging met een kwaadaardig gevormd Windows bitmap (BMP) bestand op 30 juli 2026 om 07:10:25 uur EST, vanaf een IP-adres op het RIPE-netwerk, gepresenteerd als Chrome 131.0.0 op Windows 10. Deze eerste poging was een geïsoleerd incident, niet het begin van aanhoudende activiteit. De logs tonen de dagen daarna niets verder tegen deze client. Dit is consistent met een sondeerslag (probe) afkomstig van de vroege PoC, in plaats van het begin van een bredere scan-campagne.

De continue, zich aanpassende golf van sonderingen begon apart op 3 augustus 2026 om 01:01:05 uur EDT, waarbij gebruik werd gemaakt van een vermomd PNG-bestand in plaats van het BMP-bestand uit de eerste poging. Vanaf dat moment gingen de pogingen door via een roterende set IP-adressen wereldwijd, met diverse user-agents, waaronder een vervalste versie van de Claude-SearchBot crawler van Anthropic en een ongebruikelijk eerlijke user agent, Mozilla/5.0 (CVE-2026-66066 security verification), die openlijk de CVE noemde waarop werd gesondeerd, wederom vanuit een internationaal IP-bereik.

Hoewel onze overheidsclient gebruikmaakt van beveiligingsbeoordelingsdiensten, zijn geen van deze pogingen — noch de geïsoleerde probe van 30 juli, noch de aanhoudende campagne vanaf 3 augustus — toe te schrijven aan die activiteiten. Dit was duidelijk ongeautoriseerd en, vanaf 3 augustus, een voortdurende sondering van deze ernstige kwetsbaarheid.

Voortdurende aanvalspogingen gedurende augustus 2026

De pogingen om dit gedrag te exploiteren gingen de hele maand dagelijks door, vaak tijdens de nachtelijke uren. We hebben logbewijs van aanval-frameworks die niet alleen automatiseerden, maar ook tekenen van aanpassing vertoonden; zo veranderden de pogingen naar andere varianten zodra er bepaalde aanvullende beveiligingsmaatregelen waren getroffen. Over de mate waarin dit volledig geautomatiseerd was of wat de motivatie van de aanvallers was, doen we op dit moment geen publieke uitspraken.

Tijdlijn van CVE-2026-66066: openbaarmaking, patchen en exploitatiepogingen

Datum & TijdGebeurtenis
21 juli 2026Initiële ontdekking door legitieme beveiligingsonderzoekers
22 juli 2026Onderzoekers nemen contact op met de beheerders van Ruby on Rails via een procedure voor verantwoorde openbaarmaking
29 juli 2026Kritieke ActiveStorage-update uitgebracht. Openbaarmaking en publieke trackingnummers voor de kwetsbaarheid toegewezen
29 juli 2026, 17:47:30 EDTEen publieke proof-of-concept exploit wordt naar GitHub gepusht, uren voordat onze eigen patch voltooid was
29 juli 2026, avondRietta past patches toe op getroffen klanten via de noodprocedure voor hotfixes
29 juli 2026, 23:09 ESTRietta implementeert de specifieke, geteste update bij een specifieke overheidsclient
30 juli 2026, 07:10 ESTVroege ochtend: exception logs van diezelfde overheidsapplicatie duiden op de eerste aanvalspoging vanaf een buitenlands IP-adres (geïsoleerd incident)
30 juli 2026, 20:51 EDTRuby on Rails project brengt tooling uit om te controleren op compromittering
31 juli 2026, 06:56 EDTAndré Baptista publiceert technische bevindingen op https://ethiack.com
3 augustus 2026, 01:01:05 EDTContinue, aanhoudende sonderingen beginnen met gebruik van een vermomd PNG-bestand, verschillend van de geïsoleerde poging op 30 juli

Betekenis voor Rails-applicaties die gevoelige data verwerken

De les hier is groter dan deze ene CVE. Een gecoördineerde tijdlijn voor openbaarmaking biedt verdedigers geen genadegroep. Op het moment dat een patch wordt verzonden, is de fix zelf — een publieke code diff — beschikbaar voor iedereen die bereid is deze te lezen in plaats van te wachten op een begrijpelijk verslag. Onze eigen logs bewijzen dat het gat tussen "patch gepubliceerd" en "werkende exploit geprobeerd" in uren wordt gemeten, niet in weken, ongeacht wat de embargo-datum zegt.

Dat is waarom onze noodprocedure voor hotfixes onafhankelijk bestaat van severity-scoring, initiële communicatie van de leverancier of embargo-data. We patchen op basis van de fix, niet op basis van het verslag. Voor onze klanten die gereguleerde data beheren, of het nu gaat om HIPAA-gezondheidsgegevens of overheidssystemen die gebonden zijn aan publiek vertrouwen, is dat verschil essentieel.

Hadden we een standaard proces van "melden en wachten" gevolgd, dan had deze client pas na kantooruren een werkende patch gehad, waarschijnlijk pas halverwege de ochtend wanneer iemand met autoriteit bereikbaar was om de wijziging goed te keuren. De eerste exploitatiepoging vond plaats om 07:10 uur, acht uur en één minuut nadat wij hadden gepatcht zonder op toestemming te wachten. In een conventionele goedkeuringscyclus was dat venster geen vertraging, maar een live, ongepatchte, actief getargete kritieke kwetsbaarheid die openstond tijdens de gehele periode vóór kantoortijden, zonder dat iemand wist dat er een beslissing genomen moest worden.

Al deze pogingen mislukten volledig, precies op het punt waar onze patch dit beoogde. Dat betekent niet dat er niets is gebeurd. Een maand van aanhoudende, zich aanpassende sonderingen door meerdere actoren tegen een live overheidssysteem is op zichzelf al een verhaal. Snel patchen maakte het verschil tussen een incident en een non-event. We hebben sindsdien extra hardening toegevoegd: striktere validatie van uploads, geautomatiseerde blokkering van herhaalde scanpogingen en gecentraliseerde waarschuwingen. "De exploit is mislukt" is een resultaat dat we willen behouden, geen reden om te stoppen met opletten.

Praktisch advies

Voor iedereen, en vooral voor hen die geen client van ons zijn, heb ik enkele praktische adviezen:

  • Behandel elke standalone security-release van een dependency als urgent, zelfs voordat er een CVSS-score is toegewezen. De toekenning van een score loopt vaak uren achter op het werkelijke risico. Als een leverancier een specifieke beveiligingsrelease uitbrengt, wacht dan niet op een cijfer om te bepalen hoe kritiek het is.
  • Controleer of uw Ruby on Rails-applicatie ActiveStorage gebruikt. Zo ja, en uw team heeft nog niet geüpgraded, neem deze dreiging dan zeer serieus, patch onmiddellijk en onderzoek uw blootstelling.
  • Patch ernstige kwetsbaarheden binnen enkele uren. Zorg dat er vooraf bevoegdheden voor noodwijzigingen zijn vastgesteld, zodat een fix niet geblokkeerd wordt omdat er gewacht moet worden tot iemand wakker wordt om toestemming te geven.
  • Draai dagelijks geautomatiseerde, ecosysteem-specifieke beveiligingsscans. Voor Rails betekent dit tools zoals bundler-audit (voor bekende CVE's in dependencies) en Brakeman (statische analyse voor Rails-specifieke kwetsbaarheidspatronen). In onze ervaring zijn deze nachtelijke scans sneller in het signaleren van problemen dan GitHub's eigen Dependabot, en ze zijn veel effectiever dan wachten op een periodiek extern beveiligingsauditrapport. Behandel de signalen dagelijks.
  • Behandel elke codepad die door gebruikers geüploade bestanden verwerkt als een eigen threat model boundary. Valideer bestandstypen via magic bytes, niet via content-type headers; harden Sie de policy van uw image- of document-processing library (bijvoorbeeld policy.xml van ImageMagick, door coders of delegates uit te schakelen die u niet gebruikt); en sandbox deze verwerking of voer deze uit met beperkte privileges waar mogelijk. Dit was het werkelijke aanvalsoppervlak in dit incident.
  • Stel een Web Application Firewall (WAF) in, zoals Cloudflare of AWS WAF & Shield; monitor deze en stem hem af op uw omgeving. Signature-based regels missen vaak een nieuwe payload die verborgen zit in een misvormd bestand. Behandel een WAF als één laag van verdediging, nooit als het volledige plan.
  • Voeg continu meer geautomatiseerde tests toe om er zeker van te zijn dat uw software correct werkt vóór en na dergelijke patches. Vertrouw op dit vangnet om snel te kunnen handelen onder druk.
  • Zorg voor exception monitoring en laat uw technische team dit regelmatig beoordelen. Mislukte verzoeken zijn net zo belangrijk als succesvolle. Let specifiek op POST- en PUT-verzoeken naar paden die niet bestaan; dit is een sterke indicator van vijandige sondering. Wanneer iets recurreert, voeg dan validatie en geautomatiseerde tegenmaatregelen toe (voor Rails bijvoorbeeld iets als rack-attack om herhaalde overtreder te knijpen).
  • Zorg dat uw applicatie alleen reageert op verzoeken gericht aan uw specifieke domeinnaam, en niet alleen op verzoeken die naar uw IP-adres worden gerouteerd. Cloudproviders roteren IP-adressen tussen klanten, dus dit is simpelweg goede hygiëne en vermindert ruis.
  • Configureer en bewaar logs bij uw WAF (vooral blokkeringen) en binnen uw applicatie. Zorg dat uw applicatie zowel succesvolle als mislukte authenticaties logt en beoordeel deze regelmatig.

Expertise van Rietta in Ruby on Rails

Als bedrijf is Rietta al lange tijd actief als Ruby on Rails-ontwikkelingsbureau via onze divisie Atlanta Ruby Developer. We staan bekend als een langdurige partner voor beveiligingsgevoelige industrieën met maatwerk Ruby on Rails-applicaties in hun infrastructuur. We zijn daarnaast sponsor van de Atlanta Ruby Users’ Group, een langlopende gemeenschap van Ruby-ontwikkelaars.

Persoonlijk werk ik sinds mijn masterstudie in 2006 met de programmeertaal Ruby, en professioneel met Ruby on Rails sinds 2011. Ik heb lange tijd ontwikkelaars getraind en geconsulteerd over alle aspecten van Ruby on Rails-ontwikkeling en beveiliging.