TL; DR
Per circa due mesi, un singolo npm infostealer è riemerso sotto una serie di nomi di pacchetto a rotazione mentre distribuisce un payload quasi invariato. È iniziato apertamente come forge-jsxy, generato forge-jsx3 / forge-jsx4 fratelli, poi hanno abbandonato completamente il marchio "forge" per presentarsi come infrastruttura per sviluppatori — prima zredis-typed, E più recentemente pinokio-redis.
Ogni variante porta con sé il stessa catena di strumenti interna: file denominati forge-jsx-explorer-* relayPackageServe modulo che serve a forge-jsxy-package.tgze un runtime persistente nascosto in una directory con puntatori, in modo che sopravviva all'eliminazione del pacchetto npm.
Il payload recita materiale per portafogli di criptovalute e le credenziali dello sviluppatore dall'host e le trasmette a Discord webhooks, caricamenti di HuggingFace Hub e un endpoint C2 hardcoded. Installa l'avvio automatico a livello di sistema operativo in modo che venga eseguito di nuovo dopo il riavvio e cattura l'attività degli appunti, della tastiera e dello schermo. L'ultima variante, pinokio-redissi descrive come un'integrazione con "Autodesk Forge", una descrizione che non ha nulla a che vedere con ciò che fa il codice.
| Ecosistema | npm |
| Classe di carico utile | Infostealer multistadio + agente di controllo remoto (RAT) |
| Obiettivi primari | portafogli di criptovalute, estensioni per portafogli nel browser, credenziali per sviluppatori/cloud |
| Persistenza | Runtime persistente nascosto + avvio automatico del sistema operativo (resistenti alla rimozione del pacchetto) |
| exfiltration | Rete di discordiahooks + relè, HuggingFace Hub, C2 hardcoded sulla porta 9877 |
| Intervallo osservato | Maggio 2026 – Luglio 2026 (in corso) |
| Nome più recente | pinokio-redis:1.0.127 |
Anatomia dell'attacco
Ogni variante di questa famiglia si installa attraverso la stessa forma: un pacchetto che sembra inerte nella sua pagina di elenco ma dichiara un hook postinstall, quindi il payload viene eseguito nel momento in cui il pacchetto viene installato come dipendenza. Il gancio aziona una catena a cinque stadi.
- Fase 1: materializzazione. Lo script di installazione decodifica un pacchetto codificato blob in un set di script di runtime e li scrive in una directory nascosta nella posizione di configurazione della piattaforma (le versioni forge-jsxy utilizzavano un percorso puntato .forge-jsxy/runtime/v / percorso). Poiché questa copia si trova al di fuori di node_modules, la rimozione o la non pubblicazione del pacchetto npm non rimuove l'agente in esecuzione.
- Fase 2 — persistere. La catena registra una voce di avvio automatico del sistema operativo in modo che l'agente si riavvii al riavvio. Su Windows, questo viene eseguito tramite uno script di diagnostica PowerShell nascosto; il processo dell'agente viene avviato in modalità detached e con windowsHide impostato in modo che non venga visualizzata alcuna finestra della console.
- Fase 3: eludere. Il runtime verifica la presenza di marcatori di integrazione continua ed esce silenziosamente quando rileva un ambiente CI, quindi le sandbox di build automatizzate non vedono nulla. Nelle versioni forge-jsxy, un commento nel codice sorgente affermava che un campo forgeInstall visibile era stato deliberatamente omesso da package.json "perché quel campo sarebbe stato visibile su npm" - l'operatore ha volutamente mantenuto i metadati del trigger fuori dall'elenco pubblico.
- Fase 4 — raccolta. Una volta avviato, l'agente raccoglie i dati in un'unica passata:
- Materiale adatto per un portafoglio di criptovalute. Un elenco di destinazione secret_filename_patterns.json raggruppato esegue una scansione del filesystem per wallet.dat, *.mnemonic /File .seed / *.phrase, keypair.json, Ethereum UTC– Sono presenti nel pacchetto i keystore e i keystore *.p12 / *.pfx / *.jks. Le librerie di derivazione del wallet (bip39, secp256k1, base58check e le funzioni di supporto di Solana).
- Estensioni per wallet del browser. Il modulo chromiumExtensionDbHarvest legge i database di archiviazione delle estensioni locali dei browser Chromium, ovvero la posizione in cui le estensioni del wallet basate su browser conservano i dati del proprio vault.
- Credenziali e segreti. L'agente analizza la cronologia della shell e i file contenenti segreti, legge le credenziali dello sviluppatore/cloud e quindi codifica le credenziali di HuggingFace per il caricamento.
- Input in tempo reale. Il contenuto degli appunti, l'input da tastiera e le schermate vengono acquisiti in modo continuativo.
Fase 5 — esfiltrazioneI dati raccolti lasciano l'host attraverso tre canali operativi in parallelo: Discord webhooks (discordWebhookPost) e un caricatore di relay Discord che comunica con `discord.com/api/v10` (discordRelayUpload), caricamenti di HuggingFace Hub (hfUpload) e un Endpoint C2 hardcoded raggiunto sulla porta 9877. Un relayPackageServe il modulo inoltre fornisce un ritorno forge-jsxy-package.tgz — lo stesso nome dell'artefatto in ogni ridenominazione.
Il punto strutturale importante è che le fasi 1–3 vengono eseguite al momento dell'installazione con nessuna interazione dell'utente e la fase 1 posiziona il payload da qualche parte nel pacchetto Il manager non tiene traccia. Uno sviluppatore che nota la strana dipendenza e Eseguendo npm uninstall viene rimossa la voce dall'elenco, ma non l'agente.
Il payload resiste anche a una lettura rapida. Gli script di runtime non vengono distribuiti in chiaro: una fase di codifica e distribuzione mantiene la logica operativa come un blob codificato che si espande in script leggibili solo dopo la catena di installazione lo decodifica nella directory di runtime nascosta. I file che sono visibili nell'elenco: lo spessore sottile postinstallazione e una materializzazione discontinua aiuto — rivela poco su cosa viene eseguito in definitiva. Questa consegna codificata La progettazione ha avuto un effetto misurabile sul triage: nell'arco della vita della famiglia, diverse varianti confermate sono state classificate come sicure dalla classificazione automatizzata, e il contenuto utile è risultato sufficientemente opaco da bloccare completamente la revisione automatizzata. I comportamenti che tradiscono la famiglia sono visibili solo dopo la codifica La fase viene espansa e il tempo di esecuzione viene letto direttamente.
timeline
Il carico utile della famiglia è rimasto notevolmente stabile; ciò che cambia è il nome sulla scatola. L'arco va dal marchio aperto "forgia" verso si maschera da strumenti di sviluppo non correlati.
| Data (2026) | Pacchetto: versione | Note: |
|---|---|---|
| Maggio (inizio) | forge-jsxy:1.0.81, :1.0.90 | Varianti confermate per prime: RAT con C2 crittografato con AES-256-GCM |
| che si terrà nel maggio 19 | forge-jsxy:1.0.92 / 1.0.105 / 1.0.107 / 1.0.108 | Campagna in fase di pubblicazione attiva; la versione 1.0.92 era stata inizialmente etichettata erroneamente come sicura, ma l'etichetta è stata modificata in seguito a una nuova revisione del codice. |
| Fine maggio | forge-jsx3 / forge-jsx4:1.0.122 / 1.0.123, zod-pino | Nomi di pacchetti fratelli, stessa toolchain |
| Giugno 4 | forge-jsxy:1.0.120 | Continuazione; classificato sicuro dal modello ML (un errore) |
| 21-23 giugno | forge-jsxy:1.0.121 | Il set di moduli è rimasto invariato dalla versione 1.0.120. |
| luglio 6 | zredis-typed:1.0.127 | "forge" è stato eliminato dal nome; le navi sono ancora in funzione. forge-jsxy-package.tgz and forgeAgent* chiavi di configurazione |
| luglio 7 | pinokio-redis:1.0.127 | Stessa catena di strumenti; nuovo C2; si descrive come un'integrazione "Autodesk Forge". |
Due elementi spiccano lungo la cronologia degli eventi. In primo luogo, il numero di versione 1.0.127 viene riutilizzato letteralmente sia da zredis-typed che da pinokio-redis: la nomenclatura cambia, ma la linea di build non viene azzerata. In secondo luogo, il passaggio da nomi che iniziano con "forge-*" coincide con un passaggio a nomi che si leggono come normali infrastrutture (redis, pinokio), riducendo la probabilità che uno sviluppatore legga il nome superficialmente ed esiti.
Indicatori di compromesso
Gli IOC sottostanti sono stati de-fangati. L'host C2 ruotava tra la linea forge-jsxy e l'ultima variante mantenendo la stessa porta.
| Valore | Visto in | |
|---|---|---|
| Punto finale C2 | 212.193.3[.]61:9877 | pinokio-redis:1.0.127 |
| Punto finale C2 | 79.108.162[.]160:9877 | linea forge-jsxy, zredis-typed:1.0.127 |
| Canale Exfil | discord.com/api/webhooks/… (post webhook) | tutte le varianti |
| Canale Exfil | discord.com/api/v10 (caricamento di nuovo) | tutte le varianti |
| Canale Exfil | Caricamento di HuggingFace Hub | tutte le varianti |
| Manufatto servito | forge-jsxy-package.tgz (tramite relayPackageServe) | tutte le varianti |
| File della toolchain | chromiumExtensionDbHarvest, discordRelayUpload, discordWebhookPost, hfUpload, encode-hf-credentials, forge-jsx-explorer-* | tutte le varianti |
| Elenco degli obiettivi | secret_filename_patterns.json (wallet.dat, .mnemonic/.seed/.phrase, keypair.json, UTC--, .p12/.pfx/*.jks) | tutte le varianti |
| Tempo di esecuzione nascosto | punteggiato …/.forge-jsxy/runtime/v<version>/ percorso della directory di configurazione | linea forge-jsxy |
| Persistenza di Windows | Script di avvio automatico PowerShell nascosto "forge diagnostics" | tutte le varianti |
| Installazione del trigger | Hook postinstall che richiama una catena di script di materializzazione della distribuzione. | tutte le varianti |
Il segnale di rilevamento più duraturo non è un singolo host o webhook, bensì quelli ruota — ma i nomi dei file della toolchain e forge-jsxy-package.tgz artefatto, che è rimasto invariato nonostante ogni cambio di nome.
Attribuzione e comportamento osservato
I pacchetti sono stati pubblicati sotto più di un account npm. Il forge-jsxy riga utilizzata dall'editore jacksonkaandorp2 (jacksonkaandorp2@outlook[.]com); l'ultima variante pinokio-redis è stata pubblicata da donimique (donimiqueakers@gmail[.]com). Nessuno dei due account aveva un'email verificata o un repository di sorgenti collegato. Il filo conduttore tra gli account è il catena di strumenti, non l'identità dell'editore: gli stessi nomi dei moduli, lo stesso Il file viene servito in formato .tgz e lo stesso schema di esfiltrazione si ripete indipendentemente da chi lo ha pubblicato.
Diversi comportamenti osservabili indicano un occultamento deliberato piuttosto che Raccolta eccessiva accidentale:
Il runtime viene posizionato al di fuori della cartella node_modules, in una directory nascosta, in modo che sopravviva al pacchetto che lo ha distribuito.
L'agente si arresta quando rileva un ambiente CI, limitando l'esposizione nelle sandbox di analisi automatizzate.
Il processo dell'agente viene avviato in modo separato e window-hidden.In Nelle versioni di forge-jsxy, un commento collegava l'omissione di un campo di installazione visibile al fatto che tale campo fosse "visibile su npm".
Le descrizioni pubbliche dei pacchetti non sono correlate al codice sorgente: pinokio-redis si presenta come un'integrazione con "Autodesk Forge".
Un divario di rilevamento ricorrente è degno di nota per i difensori che fanno affidamento su classificazione automatizzata: in questa famiglia sono state confermate diverse varianti classificato come sicuro da un classificatore ML prima che la revisione del codice correggesse il verdetto. Gli elementi stabili su cui un recensore può basarsi: il tempo di installazione catena, il runtime nascosto, i nomi dei file della toolchain — sono esattamente quelli che sopravvivono ai cambi di nome.
Descriviamo quanto sopra come comportamento osservato. Non attribuiamo il campagna a qualsiasi attore nominato e non facciamo alcuna affermazione sull'operatore identità o obiettivi che vanno oltre quanto dimostrato dal codice e dall'infrastruttura.
Impatto, tendenze e linee guida per i difensori
Chi è esposto. La collezione è chiaramente destinata agli sviluppatori macchine: portafogli e keystore di criptovalute, estensioni del portafoglio per browser, cronologia della shell e credenziali cloud/di servizio. Chiunque installi un pacchetto interessato — direttamente o come dipendenza transitiva — durante il la finestra in cui era in diretta è nell'ambito e la progettazione della persistenza significa che L'esposizione non termina con la rimozione del pacchetto.
Perché la perseveranza è importante. Poiché la fase 1 copia il payload in un directory di runtime nascosta e registri di fase 2 avvio automatico, il solito istinto di bonifica (disinstalla la dipendenza errata, elimina node_modules, reinstalla) non espelle l'agente. La risposta all'incidente deve cercare il runtime esterno all'albero e voce di avvio automatico, non solo il pacchetto.
La tendenza. Questa famiglia illustra uno schema che vale la pena osservare: un carico utile stabile e maturo, avvolto in un flusso di dispositivi usa e gettanomi di pacchetti che migrano da qualsiasi nome precedentemente rimosso riconoscibili, verso nomi che suonano come infrastrutture ordinarie. Basato sul nome Le liste di blocco e la reputazione degli editori invecchiano rapidamente rispetto a questo; comportamento- e i segnali basati su artefatti no.
Per sviluppatori e consumatori
Considera gli script di installazione come la principale superficie di rischio. Installa con gli script disabilitati ove possibile e rivedi qualsiasi dipendenza che dichiara un postinstallazione. Verifica e controlla attentamente le dipendenze transitive; questa classe di malware si diffonde con la stessa facilità sia tramite una sottodipendenza che tramite una dipendenza diretta.
Su un host sospetto, cerca oltre il pacchetto: cerca una directory di runtime nascosta nella posizione di configurazione della piattaforma, una voce di avvio automatico inattesa, e connessioni in uscita al webhook di Discord o agli endpoint :9877.
Si presume che qualsiasi frase di recupero del portafoglio, keystore o credenziale presente su un host interessato durante il periodo di esposizione sia stata compromessa e si procede alla rotazione.
Per registri e difensori
Avviso sugli artefatti durevoli (forge-jsxy-package.tgz, forge-jsx-explorer-* / chromiumExtensionDbHarvest / discordRelayUpload nomi dei file) piuttosto che il nome del pacchetto, che cambia.
Segnala la combinazione strutturale su cui si basa la famiglia: un postinstall che materializza gli script in un percorso config-dir nascosto più un sistema operativo registrazione all'avvio automatico — indipendentemente dalle stringhe specifiche coinvolte.
Il nome sulla confezione è cambiato almeno quattro volte; la cassa all'interno Non l'ha fatto. Il rilevamento basato su ciò che fa il codice è sopravvissuto a ogni rietichettatura effettuata finora.



