Sintesi
Il 3 marzo 2026, Xygeni ha rilevato attività sospette che interessavano il repository utilizzato per pubblicare l'azione GitHub xygeni/xygeni-action. L'attività proveniva da credenziali compromesse associate a un token di manutentore e a un'app GitHub installata sul repository.
Durante l'incidente, un attaccante ha tentato di introdurre codice dannoso nel repository attraverso una serie di pull requestsQuesti tentativi sono stati bloccati dalle regole di protezione dei rami esistenti, che hanno impedito l'unione del codice nel ramo principale del repository.
Tuttavia, l'attaccante ha successivamente sfruttato un vettore separato spostando il tag v5 mutabile per fare riferimento a un elemento dannoso commit creato durante il pull request tentativi. I flussi di lavoro che fanno riferimento a xygeni/xygeni-action@v5 potrebbero quindi recuperare il codice compromesso senza alcuna modifica visibile alle loro definizioni di flusso di lavoro.
La manomissione del tag è stata individuata il 9 marzo a seguito di segnalazioni da parte della comunità. Il tag compromesso è stato immediatamente rimosso e sono state avviate le procedure di intervento.
La nostra indagine ha accertato quanto segue:
- Nessun codice dannoso è stato integrato nel ramo principale del repository.
- C'è nessuna prova di compromissione della piattaforma SaaS di Xygeni o dati dei clienti.
- La finestra di esposizione è stata limitata ai flussi di lavoro che fanno riferimento a xygeni/xygeni-action@v5 tra 3 marzo e 9 marzo 2026.
- Il tag compromesso è stato rimosso definitivamente e non verrà ricreato.
In seguito alla scoperta della manipolazione dei tag, Xygeni ha implementato numerosi miglioramenti alla sicurezza nei suoi repository e processi di rilascio, tra cui:
- Rimozione del tag compromesso e guida alla migrazione a Riferimenti fissati tramite SHA.
- Applicazione di rilascio immutabilità attraverso i repository.
- Rafforzamento delle autorizzazioni del repository e dell'accesso dei collaboratori.
- Obbligatorio firmato crittograficamente commits per i manutentori.
- Limitazione dell'accesso in scrittura a un insieme ristretto di manutentori e amministratori.
Pubblichiamo questo rapporto per garantire la trasparenza sull'incidente, condividere le lezioni apprese e contribuire a rafforzare le pratiche di sicurezza nell'intero ecosistema di GitHub Actions.
Sebbene l'attacco abbia sfruttato una vulnerabilità nota di GitHub Actions relativa ai tag modificabili, l'incidente evidenzia anche l'importanza di una protezione completa del repository, di una gestione rigorosa delle credenziali e di una difesa multilivello. CI/CD sistemi.
Trasparenza e collaborazione sono essenziali per migliorare la resilienza della catena di fornitura del software.
Panoramica dell'incidente
Questo rapporto documenta l'indagine su un incidente di sicurezza che ha interessato il pubblico xygeni/xygeni-action Repository di GitHub Action.
Il 3 marzo 2026, un utente malintenzionato ha utilizzato credenziali compromesse associate all'automazione del repository per introdurre codice dannoso attraverso una serie di pull request tentativi. Il carico utile conteneva un impianto di comando e controllo camuffato da telemetria di versione scanner.
Le regole di protezione del ramo del repository hanno impedito con successo che il codice dannoso venisse unito al ramo principaleTuttavia, l'attaccante ha successivamente manipolato il mutabile v5 etichetta, reindirizzandolo a un commit contenente il payload iniettato. Poiché molti flussi di lavoro fanno riferimento a GitHub Actions utilizzando i tag della versione principale, questo avvelenamento delle etichette flussi di lavoro a valle consentiti che fanno riferimento xygeni/xygeni-action@v5 per recuperare il codice compromesso senza apportare modifiche visibili alla configurazione del flusso di lavoro.
In qualità di fornitore di software supply chain security utensiliXygeni gestisce infrastrutture che si integrano direttamente nello sviluppo pipelines e CI/CD ambienti. I progetti in questo ambito sono spesso bersaglio di attacchi che mirano a compromettere gli strumenti di sviluppo ampiamente utilizzati per raggiungere gli ambienti a valle.
timeline
Fase 1: Il Maligno Pull Requests (3 marzo, 10:22–10:50 UTC)
Alle 10:22 UTC del 3 marzo 2026, un attaccante ha iniziato un attacco rapido e coordinato al repository xygeni-action utilizzando due identità compromesse: il token di accesso personale (PAT) di un manutentore e la chiave privata di un'app GitHub (xygeni-onboarding-app-dev). Nei successivi 28 minuti, tre pull requests sono stati creati e chiusi, ognuno iniettando codice shell offuscato in action.yml.
L'approccio dell'attaccante è stato metodico e adattivo:
- PR # 46 (10:22–10:29 UTC): Creato dal manutentore compromesso PAT sotto il ramo feat/scanner-telemetryL'attaccante ha tentato di unire le modifiche, ma è stato bloccato dalle regole di protezione del ramo. La pull request è stata chiusa senza unione.
- Ricognizione (10:39–10:40 UTC): L'attaccante ha testato l'accesso all'app GitHub creando e cancellando immediatamente un ramo denominato accesso all'app di provaCiò ha confermato che l'app aveva i permessi di scrittura sul repository.
- PR # 47 (10:41–10:44 UTC): Un secondo tentativo utilizzando il manutentore PAT, ora sotto un ramo rinominato miglioramento/telemetria dello scanner. Di nuovo bloccato dalla protezione del ramo. L'attaccante ha tentato di utilizzare l'app GitHub per approvare la pull request, aggirando il requisito dei due revisori facendo approvare il lavoro di un'identità compromessa a un'altra. Anche questo tentativo è fallito.
- PR # 48 (10:45–10:49 UTC): I ruoli sono stati scambiati: l'app GitHub ha creato la PR (pushing) commit 4bf1d4e), e il manutentore PAT ha inviato la richiesta di approvazione. Anche questa è stata respinta dalla protezione del ramo.
Nessuna delle pull request ha raggiunto il ramo principale. Le nostre regole di protezione del ramo erano attive: il requisito di due approvazioni, la regola che l'ultimo push deve essere approvato da qualcuno diverso da chi lo ha effettuato e la restrizione sulla possibilità di aggirare queste impostazioni, il tutto combinato per bloccare ogni tentativo di merge.
Il nostro team ha rilevato l'attività anomala durante la revisione di routine delle pull request e ha avviato una risposta all'incidente alle 12:21 UTC, meno di due ore dopo la prima pull request dannosa. La risposta ha incluso la rimozione dei flussi di lavoro, la conservazione del codice dannoso per l'analisi forense e la messa in sicurezza del repository.
Fase 2: L'avvelenamento dell'etichetta
Sebbene la protezione del ramo abbia impedito con successo al codice dannoso di raggiungere il main, l'attaccante ha sfruttato un vettore separato. Utilizzando le credenziali compromesse dell'app GitHub, l'attaccante ha spostato il tag v5 mutabile in modo che puntasse a commit 4bf1d4e — il malevolo commit dalla PR #48 che esisteva ancora nell'archivio oggetti del repository anche dopo che il ramo della PR era stato eliminato.
È fondamentale sottolineare che questa manipolazione del tag non è avvenuta immediatamente dopo le pull request. I log delle attività del repository di GitHub non mostrano gli eventi di push forzato dei tag nello stesso modo delle operazioni sui branch, il che limita la possibilità di ricostruire l'esatto timestamp della modifica del tag. Tuttavia, la manomissione del tag è stata confermata quando la community ha lanciato l'allarme il 9 marzo.
Questa è l'intuizione chiave: le regole di protezione dei rami non proteggono i tag. commit La backdoor era presente nel database degli oggetti Git del repository e il tag v5, a cui facevano riferimento i flussi di lavoro a valle, poteva essere reindirizzato silenziosamente ad essa. Qualsiasi flusso di lavoro che utilizzasse xygeni/xygeni-action@v5 avrebbe scaricato il codice compromesso, senza che alcuna modifica fosse visibile nel ramo principale o nei file dei flussi di lavoro dei repository che lo utilizzavano.
Causa ultima
La nostra indagine ha concluso che la causa principale era la compromissione della chiave privata di un'app GitHub (xygeni-onboarding-app-dev) che era stata installata sul repository.
Questa app GitHub è stata originariamente creata per testare l'esperienza di onboarding sulla piattaforma di Xygeni. Aveva permessi di scrittura sul repository, permessi che, a posteriori, si sono rivelati più ampi del necessario per lo scopo previsto.
Con la chiave privata di un'app GitHub, un utente malintenzionato può:
- Genera a piacimento token di installazione di breve durata.
- Crea e approva pull requests
- Spingi committramite Git su HTTPS
- Spostare i tag: l'azione cruciale che ha reso questo incidente significativo
L'attaccante ha utilizzato sia la password personale (PAT) del manutentore compromessa, sia le credenziali dell'app GitHub in un tentativo coordinato: quando una singola identità non era sufficiente a eludere le protezioni, le due identità venivano utilizzate in tandem, una per creare e l'altra per approvare.
Le modalità esatte con cui la chiave privata è stata sottratta sono ancora oggetto di indagine. Le chiavi private delle app GitHub (file .pem) possono essere divulgate a causa di flussi di lavoro configurati in modo errato, computer di sviluppatori compromessi o sistemi di archiviazione segreti non sicuri.
Comportamento dannoso del payload
Il codice iniettato era un impianto di comando e controllo compatto. Era progettato per funzionare silenziosamente insieme allo scanner legittimo, eseguendosi in tre fasi:
- Registrazione. L'impianto contatta un server C2 all'indirizzo 91.214.78.178 (mascherato tramite DNS wildcard nip.io come security-verify.91.214.78.178.nip.io), inviando il nome host, il nome utente e la versione del sistema operativo del runner.
- Ciclo di polling. Per 180 secondi (un intervallo tipico dei timeout dei job CI), l'impianto interroga il server C2 ogni 2-7 secondi per verificare la presenza di comandi da eseguire.
- Esecuzione dei comandi. Tutti i comandi ricevuti vengono eseguiti tramite eval, con output compresso (zlib), codificato in base64 e ritrasmesso al server C2.
Inghiottiti silenziosamente, i nomi delle variabili erano volutamente concisi e l'intervallo di campionamento era randomizzato per eludere il rilevamento dei modelli di traffico.
Se l'impianto fosse stato eseguito su un runner CI, l'attaccante avrebbe avuto accesso a GITHUB_TOKEN, segreti del repository, codice sorgente e potenzialmente chiavi di firma degli artefatti. L'impianto avrebbe potuto consentire l'esecuzione di comandi su un runner CI se eseguito all'interno di un flusso di lavoro che faceva riferimento al tag compromesso.
In questo momento, abbiamo Non vi è alcuna prova che il payload sia stato eseguito in un ambiente CI del cliente. o che segreti siano stati trafugati attraverso l'azione.
Infrastruttura C2
Il server C2 era ospitato presso Partner Hosting LTD (AS215826), registrato a 71-75 Shelton Street, Covent Garden, Londra, un indirizzo di ufficio virtuale comunemente utilizzato. L'infrastruttura era stata appena predisposta (la sottorete era stata modificata l'ultima volta solo 5 giorni prima dell'attacco) e l'IP era già associato a RAT, infostealer e loader nei feed di intelligence sulle minacce. L'infrastruttura e gli strumenti indicano un attaccante capace e familiare con CI/CD ambienti.
Valutazione dell'esposizione
Osservazioni chiave
I tag mutabili sono un rischio noto, ma l'inerzia è potente
L'ecosistema di GitHub Actions presenta un problema ben documentato: i tag modificabili. Quando gli utenti fanno riferimento a action@v5, si fidano del fatto che il tag punti a codice sicuro. Tuttavia, i tag possono essere forzati da chiunque abbia i permessi di scrittura. Questo è il principale vettore di attacco alla catena di fornitura di GitHub Actions, e ne eravamo a conoscenza, eppure la nostra documentazione continuava a indirizzare gli utenti a @v5.
La protezione dei rami non è protezione dei tag
Le nostre regole di protezione dei rami hanno funzionato esattamente come previsto. Hanno impedito che il codice dannoso venisse unito al ramo principale. Ma l'attaccante non aveva bisogno di unire i rami, gli bastava un commit nel repository (che ogni ramo PR fornisce) e la possibilità di spostare un tag. La protezione del ramo ci ha dato una falsa sensazione di sicurezza completa.
Le nuove funzionalità non offrono protezione retroattiva
GitHub ha introdotto rilascio immutabilità Nell'ottobre 2025 verrà introdotta una funzionalità che impedisce la modifica dei tag associati alle release. Avevamo già preso in considerazione questa possibilità, ma non ne avevamo compreso appieno le implicazioni.
- Protegge solo i tag associati alle release di GitHub, non i tag autonomi.
- Non offre protezione retroattiva: le versioni esistenti create prima dell'attivazione della funzionalità rimangono modificabili.
- Le regole di protezione dei tag (una funzionalità separata) devono essere configurate indipendentemente.
Se avessimo abilitato l'immutabilità delle release e ci fossimo assicurati che il tag v5 fosse associato a una release protetta, l'avvelenamento del tag non sarebbe riuscito.
Ambiti delle app GitHub eccessivamente permissivi
L'app GitHub aveva permessi di scrittura superiori alle sue effettive necessità operative. In un'organizzazione complessa con molteplici app, bot e integrazioni, è facile che i permessi si accumulino oltre il necessario. Ogni permesso aggiuntivo rappresenta un'ulteriore superficie di attacco.
Correzioni ai registri pubblici
Il rapporto dei ricercatori è stato fondamentale per allertare la comunità e apprezziamo la loro rapida risposta. Tuttavia, la nostra indagine interna ha rilevato alcuni dettagli che differiscono dalla loro versione dei fatti:
- La cronologia dell'avvelenamento delle etichetteIl rapporto del ricercatore colloca lo spostamento del tag v5 approssimativamente alle 10:49 UTC del 3 marzo, immediatamente dopo la chiusura delle PR. La nostra indagine non ha potuto confermare questa tempistica: gli eventi di push forzato del tag non vengono registrati nel registro delle attività del repository di GitHub. Sappiamo che il tag è stato avvelenato in un momento successivo all'azione malevola. commit è stato creato e prima che la comunità lo scoprisse il 9 marzo.
- Migliori commit non era "firmato con l'indirizzo email di un manutentore". Il rapporto del ricercatore descrive il primo malizioso commit come “firmato con l’indirizzo email del manutentore”, ma questo confonde i metadati dell’autore git con la firma crittografica: si tratta di cose fondamentalmente diverse. commit non era firmato crittograficamente. L'attaccante ha semplicemente impostato il campo git author con l'email di un altro manutentore, cosa che chiunque può fare, poiché i metadati di git author sono auto-dichiarati e non autenticati. commit è stato effettuato il push utilizzando il PAT del manutentore compromesso; il manutentore la cui email è stata utilizzata non è stato compromesso e compare nel registro delle attività del repository solo a partire dalle 12:21 UTC come parte del team di risposta all'incidente.
- Le identità coinvolteIl ricercatore ha descritto l'identità del manutentore e il bot dell'app GitHub come prova di "credenziali rubate piuttosto che di azioni interne". Possiamo confermare che il PAT classico di un manutentore e la chiave privata dell'app GitHub sono stati compromessi. Entrambi sono stati utilizzati dallo stesso attaccante esterno. La PR #48 appare sotto l'utente fantasma perché è stata creata dall'installazione dell'app GitHub, non da un account umano eliminato.
- Il numero di repository interessatiIl rapporto del ricercatore faceva riferimento a oltre 137 repository che utilizzavano @v5. La nostra analisi dei risultati della ricerca di codice su GitHub non ha confermato tale cifra. Al momento della nostra ultima analisi, non abbiamo trovato repository pubblici che utilizzassero attivamente xygeni/xygeni-action@v5 in flussi di lavoro eseguibili. I riferimenti identificati corrispondevano a esempi di documentazione all'interno dei repository Xygeni, che sono stati successivamente aggiornati. In pratica, la maggior parte dei clienti utilizza il download dello scanner tramite CLI e la funzionalità Managed Scan di Xygeni, che richiama internamente l'azione e utilizza una versione con SHA bloccato e validata internamente, non influenzata dalla manipolazione del tag. Poiché GitHub Code Search indicizza solo i repository pubblici, non possiamo determinare con certezza al 100% se i repository privati possano aver fatto riferimento al tag. Sulla base delle informazioni disponibili, l'effettiva esposizione a valle sembra essere significativamente inferiore a quella inizialmente riportata.
[Aggiorneremo questa sezione al termine delle indagini.]
Azioni di risposta
Risposta immediata (3 marzo)
- Le richieste di pull dannose sono state segnalate e bloccate (la protezione del ramo ha impedito la fusione).
- Il codice dannoso è stato estratto e conservato per l'analisi forense.
- Dominio C2 e IP registrati come indicatori di compromissione
- L'app GitHub compromessa (xygeni-onboarding-app-dev) è stata rimossa dal repository.
- Tutti i PAT contributori sono stati ruotati
- I registri di controllo del repository sono stati esaminati: nessuna prova di precedenti fusioni non autorizzate
Guida alla bonifica
Interventi di bonifica (9-10 marzo)
- Il tag v5 compromesso è stato rimosso
- Rilascio dell'immutabilità è stato abilitato per il repository e applicato a livello globale su tutti i repository di proprietà di Xygeni.
- Le norme di protezione delle filiali sono state inasprite, includendo la firma obbligatoria commits (Xygeni utilizza hardware commit firma)
- Il tag v5 non è stato ricreato intenzionalmente, per chiarire che era stato compromesso e per incoraggiare la migrazione verso riferimenti SHA-pind.
- La documentazione è stata aggiornata per fare riferimento al completo commit SHA (13c6ed2797df7d85749864e2cbcf09c893f43b23) corrispondente alla versione 6.4.0
- GitHub Actions è stato temporaneamente disabilitato sul repository a titolo precauzionale.
- I permessi di scrittura erano limitati: solo due responsabili designati e due amministratori del repository mantenevano l'accesso in scrittura.
Per gli utenti di xygeni-action
Se stavi utilizzando xygeni/xygeni-action@v5, dovresti:
- Aggiorna immediatamente il tuo flusso di lavoro da fissare alla cassaforte commit SHA:
uses: xygeni/xygeni-action@13c6ed2797df7d85749864e2cbcf09c893f43b23
- Verifica i log della tua CI per qualsiasi connessione in uscita verso 91.214.78.178 o security-verify.91.214.78.178.nip.io nel periodo compreso tra il 3 e il 9 marzo 2026.
- Ruota tutti i segreti che sono stati esposti ai runner CI durante quel periodo.
- In alternativa, puoi utilizzare un Download e verifica dello scanner diretto
Perché non lo abbiamo reso pubblico il 3 marzo
Questa è una domanda alla quale dobbiamo dare una risposta onesta.
Il 3 marzo, quando il nostro team ha risposto alle pull request dannose, la valutazione è stata che l'attacco era stato completamente contenuto nella fase di pull request. Le regole di protezione del ramo avevano funzionato. Nessun codice dannoso era stato unito al ramo principale. Nessun runner CI aveva eseguito il payload. Il PAT compromesso era stato ruotato, l'app GitHub era stata rimossa e i log di controllo del repository non mostravano alcuna prova di precedenti unioni non autorizzate. L'incidente è stato classificato come di gravità media (P2) - un tentativo di intrusione bloccato.
In base a questa valutazione, non si ritenne necessaria alcuna divulgazione pubblica. Col senno di poi, tale valutazione si rivelò incompleta.
Ciò che ci è sfuggito è stato l'avvelenamento del tag. Il tag v5 era stato spostato silenziosamente per puntare al tag dannoso commit, ma questo non era visibile nelle stesse superfici di audit che stavamo esaminando. I log delle attività del repository di GitHub registrano le modifiche dei tag di superficie in modo diverso dalle operazioni sui rami, il che ha reso la modifica meno visibile durante l'indagine iniziale. La nostra risposta all'incidente si è concentrata sul vettore di attacco visibile: il pull requests e la filiale principale — e non hanno verificato se le etichette fossero state manomesse.
Col senno di poi, questa è una delle lezioni fondamentali di questo incidente: non si può rivelare ciò che non si conosce. La nostra risposta del 3 marzo è stata rapida ed efficace contro la minaccia che avevamo individuato. Ma l'attaccante aveva un secondo vettore, più subdolo, che è rimasto inosservato per sei giorni, finché la comunità non lo ha scoperto.
Divulgazione pubblica (9 marzo)
Il 9 marzo 2026, i membri della comunità hanno aperto la questione #54, mettendo in discussione il codice dannoso e il tag v5 compromesso. I ricercatori hanno pubblicato un'analisi dettagliata che ha contribuito a sensibilizzare l'intero ecosistema.
Desideriamo riconoscere il ruolo del ricercatore nell'amplificare l'allerta e nel fornire indicazioni concrete agli utenti interessati. Vogliamo inoltre chiarire alcuni dettagli del suo rapporto laddove la nostra indagine interna è giunta a conclusioni diverse: affronteremo questi punti nella sezione Correzioni.
Lezioni per l'ecosistema
- Azioni di blocco tramite SHA, non tramite tagI tag modificabili rappresentano la più grande superficie di attacco nell'ecosistema di GitHub Actions. Utilizzare azione@ in tutti i flussi di lavoro di produzione.
- Comprendere i limiti di ciascuna funzionalità di sicurezzaLa protezione dei rami protegge i rami. La protezione dei tag protegge i tag. L'immutabilità delle release protegge le release. Non sono intercambiabili e gli spazi tra di esse sono proprio i luoghi in cui operano gli aggressori.
- Verifica incessantemente le autorizzazioni dell'app GitHubOgni applicazione installata con accesso in scrittura rappresenta un potenziale vettore di movimento laterale. Applica il principio del minimo privilegio, ruota le chiavi e rivedi periodicamente quali applicazioni sono installate sui repository critici.
- Trattare i runner CI come ambienti ostiliIl monitoraggio del traffico di rete in uscita, i runner effimeri e l'isolamento dei segreti non sono opzionali per i repository nella catena di fornitura del software.
- Le nuove funzionalità di sicurezza richiedono un'adozione proattivaLa funzionalità di immutabilità delle release di GitHub era disponibile da mesi prima di questo incidente. Le funzionalità non abilitate non offrono alcuna protezione: la sicurezza non è un'impostazione predefinita.
- unsigned commitpossono avere identità falsificate. Incitare commit autore e commitI campi ter sono auto-dichiarati: chiunque può impostarli su qualsiasi valore. Senza crittografia commit firma (GPG, SSH o S/MIME), non vi è alcuna garanzia che un commit è stato effettivamente scritto dalla persona che dichiara di essere. In questo incidente, l'attaccante ha impostato l'autore del primo messaggio dannoso commit all'email di un altro manutentore, creando una falsa attribuzione. Richiede la firma commitLe regole di protezione dei rami tramite s eliminano questo vettore.
- La complessità aumenta la superficie di attaccoL'interazione tra PAT, GitHub Apps, regole di protezione dei branch, semantica dei tag e immutabilità delle release ha creato un panorama in cui l'attaccante ha trovato falle che nessuna di queste funzionalità copriva singolarmente. Semplifica dove puoi. Comprendi il modello di minaccia completo, anche quando non puoi.
Indicatori di Compromesso (IOC)
| Tipo | Valore |
|---|---|
| Indirizzo IP | 91.214.78.178 |
| Dominio C2 | security-verify.91.214.78.178.nip.io |
| Punti terminali C2 | /b/in (registrazione), /b/q (assegnazione compiti), /b/r (esfiltrazione) |
| Intestazione di autenticazione | XB: sL5x#9kR!vQ2$mN7 |
| ASN | AS215826 (Partner Hosting LTD) |
| server | nginx/1.18.0 (Ubuntu) |
| TLS | Certificato autofirmato |
Ringraziamenti
Ringraziamo i ricercatori di sicurezza e i membri della comunità che hanno segnalato questo problema, compresi i contributori al problema #54 e ai ricercatori per le loro analisi pubbliche. Trasparenza e collaborazione sono gli strumenti per rendere la catena di fornitura del software più resiliente per tutti.





