Il developer che ha visto tutto crollare
Marco lavora come DevOps in una media azienda tech di Milano. È il 14 giugno, sono le 9:47 del mattino. Sta sorseggiando il primo caffè della giornata quando riceve una notifica Slack dal sistema di monitoring. Il server di integrazione continua mostra un errore insolito: un componente che non dovrebbe cambiare da mesi risulta modificato.
«Ho pensato a un errore di cache», mi racconta. «Poi ho visto il diff». Il codice che aveva scritto e testato per mesi conteneva adesso una funzione che non aveva mai visto. Un piccolo frammento, nascosto tra centinaia di righe. Sembrava innocuous. Ma quando Marco ha tracciato l'origine, ha trovato qualcosa che gli ha gelato il sangue: il commit proveniva da una dipendenza esterna, un pacchetto che il suo team scaricava automaticamente da npm ogni notte.
Quella dipendenza era stata compromessa. E non era sola.
Nelle ore successive, mentre Marco e il suo team cercavano di capire l'entità del danno, la notizia esplodeva nei circuiti della cybersecurity: i ricercatori di ReversingLabs avevano scoperto un pattern exploit critico nelle pipeline CI/CD di GitHub. L'hanno chiamato Cordyceps, come il fungo parassita che controlla le formiche. Centinaia di repository erano già stati infettati.
Il virus nelle tubature del codice
Per capire perché questa scoperta ha fatto tremare l'intera comunità developer, devi capire come funziona il moderno sviluppo software. Oggi nessuno scrive più tutto da zero. Ogni progetto usa librerie esterne, framework pubblici, dipendenze scaricate da registri come npm, PyPI, Maven. Sono mattoni costruttivi che milioni di sviluppatori usano ogni giorno.
Le pipeline CI/CD sono il cuore pulsante di questo sistema. Ogni volta che un developer fa un push, il sistema automaticamente compila, testa, analizza e sometimes pubblica il codice. È un processo che richiede fiducia cieca: il sistema si fida che le dipendenze siano sicure, che i credential siano protetti, che i workflow non siano stati manomessi.
E qui sta il problema.
I ricercatori hanno identificato quello che chiamano un "exploitable pattern", una sequenza di configurazioni deboli che permette a un attaccante di hijackare letteralmente un workflow intero. Non serve essere un genio dell'hacking. Serve solo che qualcuno, in qualche punto della catena, abbia sbagliato a configurare i permessi.
Il meccanismo è subdolo. Un attacker inserisce codice malevolo in un pacchetto apparentemente legittimo. Quel pacchetto viene scaricato dalla pipeline. Il workflow, che ha credential elevati per deployare in produzione, esegue il codice senza fare domande. In pochi secondi, il malware si diffonde a tutti i sistemi che usano quella dipendenza.
I numeri sono impressionanti. Solo nella campagna identificata da ReversingLabs, oltre 300 repository GitHub risultano esposti. Ma il dato più inquietante è un altro: il pattern Cordyceps non è una vulnerabilità di un singolo strumento. È una classe di debolezze che esiste in centinaia di configurazioni diverse, in migliaia di progetti.
Come funziona l'attacco passo dopo passo
Immaginiamo la scena. C'è un developer, chiamiamolo Luca, che lavora a un progetto open-source. Il suo repository ha un workflow GitHub Actions che ogni notte esegue dei test automatici e poi pubblica il pacchetto su npm.
Il problema inizia con un errore banale di configurazione. Luca, come molti developer, ha dato al workflow il token con permessi di scrittura su tutto il repository. È comodo, veloce, nessuna seccatura. Quello che Luca non sa è che quel token diventa accessibile a qualsiasi codice che il workflow esegue.
Un attacker, intanto, sta cercando vulnerabilità in questo tipo di configurazioni. Trova il repository di Luca. Nota che il workflow usa una dipendenza poco nota, un pacchetto con qualche centinaio di download al mese. È il candidato perfetto.
L'attacker contatta il maintainer del pacchetto, magari con una finta proposta di collaborazione. Oppure trova che quel maintainer ha le sue stesse debolezze di configurazione. In un modo o nell'altro, riesce a pubblicare una nuova versione del pacchetto con un payload nascosto.
La notte, il workflow di Luca scarica l'ultima versione. Il codice malevolo viene eseguito con i permessi del workflow. A questo punto l'attacker può fare praticamente tutto: rubare i credential, modificare il codice sorgente, inserire backdoor, diffondere il malware a chiunque scarichi il pacchetto pubblicato.
Il bello (per l'attacker) e il brutto (per le vittime) è che tutto sembra legittimo. Il commit c'è, il workflow ha funzionato, il pacchetto è stato pubblicato. Nessun allarme, nessun alert. Solo molto tempo dopo qualcuno si accorgerà che qualcosa non va.
E nel frattempo, il veleno si è già diffuso.
Il conto che nessuno vuole pagare
Le conseguenze di un attacco del genere sono difficili da quantificare, ma facili da immaginare.
Primo danno: la fiducia. Quando un progetto viene scoperto compromesso, gli utenti smettono di usarlo. I maintainer passano giorni a verificare che il codice sia pulito. Le aziende che dipendono da quelle librerie devono auditare tutto il loro codebase.
Secondo danno: economico. Il tempo developer è costoso. Le aziende devono pagare persone per ricostruire la catena di dipendenze, per verificare ogni singola linea di codice, per comunicare ai clienti che il prodotto è al sicuro (o non lo è).
Terzo danno: reputazionale. In un mercato dove la sicurezza è diventata un requisito minimo, essere associati a una breach è un marchio che non si cancella facilmente.
E poi c'è il danno a cascata. Ogni progetto compromesso può diventare il vettore per infettare altri progetti. È la legge del domino applicata alla supply chain del software.
Come difendersi quando il guardiano diventa il bersaglio
La buona notizia è che Cordyceps non è un bug impossibile da risolvere. È un pattern di configurazione errata, e come tale si può correggere.
La prima regola è il principio del minimo privilegio. Ogni workflow, ogni token, ogni credential deve avere esattamente i permessi necessari e niente di più. Se il tuo workflow deve solo leggere il codice, non deve avere permessi di scrittura. Se deve solo pubblicare un pacchetto, non deve avere accesso all'intero repository.
La seconda regola è l'isolamento. Ogni job nella pipeline dovrebbe girare in un ambiente separato, con credential separati. Se un job viene compromesso, l'attacker non dovrebbe poter accedere automaticamente a tutti gli altri.
La terza regola è la verifica. Prima di scaricare una dipendenza, controlla chi la mantiene, quando è stata aggiornata l'ultima volta, se ci sono warning di sicurezza. Strumenti come dependabot o Snyk possono aiutare, ma nessun tool sostituisce l'attenzione umana.
La quarta regola è il monitoraggio. Se qualcosa cambia nel tuo workflow senza che tu l'abbia fatto, devi saperlo. Gli alert di sicurezza sulle modifiche non autorizzate possono fare la differenza tra un attacco bloccato in tempo e un disastro.
Per le aziende che vogliono un livello di protezione in più, esistono soluzioni dedicate come MailSniper che permettono di monitorare le comunicazioni legate alla supply chain, interceptando tentativi di phishing mirato ai developer o avvisi di sicurezza falsi che cercano di convincere ad aggiornare dipendenze compromesse.
La domanda che non vuoi farti
Il caso Cordyceps ci dice qualcosa di importante: la sicurezza del software moderno non dipende solo dal codice che scrivi. Dipende dalla configurazione degli strumenti che usi, dalla fiducia che accordi alle dipendenze, dalla consapevolezza del tuo team.
Ogni giorno, migliaia di pipeline girano in silenzio, scaricando codice da fonti che nessuno ha verificato. La maggior parte delle volte va tutto bene. Ma basta una volta, un solo errore di configurazione, un solo pacchetto infetto, e l'intera catena crolla.
La prossima volta che configuri un workflow, fermati un secondo. Guarda i permessi che stai assegnando. Chiediti: se qualcuno compromettesse questa pipeline, quanto danno potrebbe fare?
La risposta potrebbe sorprenderti.