En GitHub‑konto blev overtaget. Timer senere lå trojanske versioner af keyv og søsterpakker på npm. Og ja, de bar gyldige provenance‑attestater. Ikke forfalskede. Optjent gennem legitime GitHub Actions‑workflows, som var sat op til at signere udgivelser. Det er kernen i Shai‑Hulud‑angrebet, som ramte 4. august 2026 ifølge Aikido.
Det lyder som en detalje. Det er det ikke. For når angrebet kan opfylde forsyningskædens formelle krav på papiret, så ryger en stor del af den komfort sikkerhedsteams har lænet sig ind i de sidste to år. VentureBeat beskriver det præcist: ormen forfalskede ikke sikkerhedstjekket. Den bestod det.
Hvad der skete og hvor hurtigt det gik
Vedligeholderen af keyv fik sin GitHub‑konto kompromitteret. Keyv er en lille nøgle‑værdi‑bibliotekspakke, men med stor udbredelse på npm, omkring 127 millioner ugentlige downloads ifølge VentureBeat og Aikido. Inden for få timer dukkede forgiftede versioner af keyv og flere relaterede cache‑pakker op på npm med en credential‑stjælende payload.
Midt på dagen talte Aikido mindst 868 kompromitterede pakker på tværs af 1.381 versioner og estimerede over to milliarder månedlige installs på tværs af dem. JFrog sporede uafhængigt kampagnen på tværs af mere end 400 pakker og 1.700 forgiftede versioner. Tallene matcher ikke helt, og det er vigtigt: Aikido og JFrog har forskellige metoder og tidspunkter for opgørelsen. Begge peger på et bredt udbrud med høj trafik.

Hvorfor det her skærer igennem forsvarslag
Angrebet lykkedes ikke, fordi nogen kun faldt for en phishing‑mail. Det lykkedes, fordi vedligeholderens konto havde adgang til at skubbe til main og udløse udgivelses‑workflows, der automatisk signerer og attesterer artefakter. Kode blev skubbet. Release blev klippet. GitHub Actions kørte. npm udgav. Sigstore‑bundle fulgte med. Hele kæden stod i grønt.
Til revisorens øjne lignede udgivelserne derfor rene. Provenance fortæller, hvorfra et build kom, og hvilken workflow der byggede det. Den garanterer ikke, at den person, der trykkede på knappen, burde have gjort det den dag. Det er den kolde sandhed her.
Det tekniske angrebsflow uden fyld
Ifølge Aikido blev to filer, setup.mjs og Math_Symbol.js, lagt direkte på main i de berørte repos, og package.json fik en preinstall‑krog, der kørte setup.mjs ved npm install. Dernæst blev nye versioner skåret, så den vedligeholder‑styrede GitHub Actions‑pipeline byggede og publicerede med gyldig provenance.
VentureBeat refererer desuden et JFrog‑spor i opensearch‑js’ workflow, hvor et OIDC‑token blev anmodet under Actions‑kørslen, byttet til en publish‑rettighed og dernæst brugt til at udstede en Sigstore‑bundle via Fulcio og Rekor. Oversat: workflowet selv udstedte et legitimt stempel, for det var sat op til at gøre netop det.
Provenance hjalp ikke her
Provenance er designet til at sikre integritet på kæden fra kilde til artefakt. Den siger, at en release kom fra repo X, workflow Y, commit Z. Og det tjekkede ud. Alt var sandt. Problemet var ikke sandheden i attesten, men autoriteten bag handlingen. En overtaget konto kan gøre alt, som kontoejeren må. Inklusive at producere sand dokumentation for en ond ændring.

Derfor holder argumentet om, at flere signaturer alene redder dagen, ikke. De skal kombineres med politiske og tekniske spærrer: godkendelser, adskillelse af roller, tokens der ikke kan byttes bredt, og workflows der ikke kan publicere, bare fordi nogen skubbede til main på et forkert tidspunkt.

Hvad payloaden gjorde i praksis
Payloaden havde ét job: finde nøgler. Når en udvikler eller en CI‑runner installerede en forgiftet version, eksfiltrerede malwaren adgangstokens og hemmeligheder, den kunne nå. Ifølge VentureBeat med henvisning til Aikido og JFrog gik den specifikt efter npm‑udgiverrettigheder og derefter bredere sky‑nøgler og CI‑hemmeligheder.
Det forklarede spredningen. Med et fundet npm‑publish token i et kompromitteret miljø kunne angriberen bagdørre flere pakker, som offeret kontrollerede. Så blev hver nye maintainer en ufrivillig distributionsnode. Aikido beskrev, at der dukkede nye kompromitterede pakker op hvert par minutter på sit højdepunkt. Eksfiltrationen blev endda markeret i offentlige GitHub‑repos med etiketten Shai‑Hulud, som blev navnet på kampagnen.
Konsekvenser for CI og release‑politik
Det hårde punkt: et workflow, der automatisk klipper release og publicerer fra en maintainer‑konto, kan misbruges til at udstede legitime attestater for ondsindet kode. Det kræver konkrete procesændringer.
Adskil udviklerkonti fra release‑identiteter. Gør publicering til en servicekonto, der kun kan noget, når en uafhængig godkendelse er givet. Læg approvals på tværs af teams, ikke kun repo‑ejeren. Og begræns OIDC‑roller, så en Action kun kan udstede tokens til det mindste, der skal bruges, og kun fra bestemte job og grene.
Token‑livscyklus og OIDC uden illusionsnumre
Kortlivede tokens er gode, men ikke magiske. Her blev tokens udstedt legitimt under et kompromitteret run. Indfør derfor constraints på audience, branch, environment og jobnavn ved OIDC‑udstedelse. Log og alarmér på anmodninger uden for normale tidsvinduer. Rotér alle publish‑tokens ved mistanke, ikke kun for ét repo. Og brug per‑repo og per‑org scopes, ikke globale nøgler.
Det er sjældent banalt i praksis, for mange legacy‑workflows bruger brede tokens af bekvemmelighed. Det er her, arbejdet ligger.

Pakke‑godkendelse og interne spejle
Et centralt spejl af eksterne pakker med whitelist og policy‑checks havde købt tid. Kræv ekstra signaturer for kritiske miljøer, fx at artefaktet både skal have provenance fra upstream og en intern attest fra jeres eget build‑spejl. Og bloker auto‑opgraderinger til x.y.z for pakker under aktiv hændelse, så transitive afhængigheder ikke slæber forgiftede builds ind midt på en tirsdag.
Start med få, vigtige kæder. Man behøver ikke løse hele npm på dag ét.
Overvågning og beredskab der duer
Detektion handler om få, tydelige signaler, ikke flere dashboards. Prioritér disse som førstelinje:
- Uventede publish‑events fra maintainer‑konti, især uden for arbejdstid
- OIDC‑anmodninger fra GitHub Actions‑jobs, der normalt ikke udsteder tokens
- Pludselige spikes i nye versionsudgivelser på tværs af en organisations repos
- Installer‑kroge i package.json, der dukker op i velkendte pakker
Når alarmen går, isolér self‑hosted runners først. Rotér npm‑, GitHub‑ og cloud‑nøgler i prioriteret rækkefølge. Slå midlertidige udgivelsesstop til for admin‑konti. Og rul hurtigt tilbage til sidste kendt sunde version via spejl eller lock‑fil.
Virker modmidlerne?

Provenance og Sigstore hjælper stadig. De sætter loft for, hvor meget angriberen kan forfalske uden adgang til jeres kæde. Men de stopper ikke en angriber, der ejer kontoen og workflowet. GitHub Actions‑politikker, environments og approvals kan bryde kæden, men kun hvis de kræver godkendelse fra en anden identitet end den, der skubbede koden.
Automatiserede scannere kan fange kendte mønstre, som en ny preinstall‑krog eller filnavne som setup.mjs i uventede repos. Alligevel vil der være blind spots. Der skal være en manuel bremse: blokér publicering uden for release‑vinduer, eller kræv hardware‑nøgle‑godkendelse for at løfte en release fra staging til public.
Det her følger en trend
VentureBeat peger på CrowdStrike’s 2026 Threat Hunting Report, der forudsagde netop den type angreb med registries og CI som primære mål. npm‑økosystemet er i centrum for registrysvindlerier, hedder det i rapporten, og stod for 87 procent af de kendte registrysager i første halvår. Shai‑Hulud passer ind i det billede.
Konklusionen: fokusér ikke kun på tyveri af kildekode. Angrebet er lige så ofte selve release‑fabrikken.
Hvem har ansvaret for skiftet
Det er et ledelsesanliggende, ikke kun et udviklerproblem. Sikkerhed og platform skal sætte politikkerne. DevOps og repo‑ejere skal bygge dem ind. Produktledere skal acceptere, at enkelte releases vil vente på en approval. Og topledelsen skal godkende, at release‑hastighed viger, når røde flag blinker. Ellers bliver kompromiserne truffet nede i kælderen, hvor der er travlt.
Prioriteringer der gør en forskel i morgen
Lav kompleksitet, høj effekt:
- Slå obligatoriske approvals til for publiceringsjobs i GitHub Actions
- Indfør per‑repo publish‑tokens med mindst mulige rettigheder, rotér nu
- Monitorér OIDC‑audience og tidspunkter, alarmér uden for releasevinduer
Høj effekt, kræver projektkapacitet:
- Adskil release‑identitet fra udviklerkonti og flyt publicering til en isoleret servicekonto
- Indfør internt registry‑spejl med policy‑gate og krav om intern attest før produktion
- Etabler environments i Actions med hardware‑nøgle‑krav for promotion til public
Uenigheder og åbne spørgsmål
Tallene er ikke fuldt afstemt. Aikido rapporterede 868 pakker og 1.381 versioner ved middagstid, mens JFrog talte over 400 pakker og 1.700 versioner. Begge dele er via VentureBeat og Aikidos egen blog. Metoderne kan forklare forskellen, men en direkte bekræftelse fra JFrog vil være nyttig.
Typer af stjålne credentials er nævnt bredt som npm‑tokens, CI‑hemmeligheder og sky‑nøgler. Den præcise fordeling i faktiske hændelser er uklar. Her savnes yderligere detaljer fra Aikido, JFrog eller berørte organisationer. Og så er der basale fakta fra GitHub og npm, fx hvilke 2FA‑krav der var aktive på den overtagne konto.
Langsigtede følger for npm og pakkehåndtering
For npm‑økosystemet peger pilen mod strammere publish‑politik. For eksempel bredere krav om 2FA for maintainere, stærkere verifikation af release‑workflows og mulig throttling ved usædvanlige mønstre af nye versioner fra kendte konti. Der er også en politisk side: hvor meget ansvar har registries for at stoppe en udbredelse, når angrebet er legitimt signerede releases?
Økonomisk kan større virksomheder vælge interne spejle og private scopes mere aggressivt. Det trækker noget af åbenheden ud af økosystemet, men skalerer bedre risikomæssigt. Ikke kønt, men forståeligt.
Kort faktabrief til sikkerhedsteams
- Tidspunkt: 4. august 2026 rapporteret som kompromisdag af Aikido
- Vektor: GitHub‑konto for keyv‑maintainer overtaget, push til main, release klippet, Actions publicerede
- Payload: credential‑stjælende orm via preinstall‑krog i package.json
- Udbredelse: Aikido talte 868 pakker og 1.381 versioner, JFrog 400+ pakker og 1.700 versioner
- Trust‑signal: gyldig provenance attesteret via maintainerens egne workflows, ikke forfalsket
- Nøglekilder: VentureBeat og Aikidos tekniske blogpost
Hvad der bør ske nu uden store armbevægelser
Stands automatisk publicering fra maintainer‑konti, indtil approvals er slået til. Rotér udgiver‑tokens og revokér alt, der ikke er per‑repo. Sæt alarmer på OIDC‑udstedelser og publikationer uden for releasevinduer. Og opret et minimalt internt spejl for de mest kritiske pakker, så rollback kan ske på minutter, ikke dage.
Det er kontant, ja. Men effekten mærkes først, når en releasekandidat ikke går i luften, før en anden har set den. Det er pointen.