
Controllo IOC per l'attacco alla supply chain npm TanStack/Mini Shai-Hulud (CVE-2026-45321)
# Attacco alla supply chain Mini Shai-Hulud — Controllore IOC
```bash
curl -fsSL https://raw.githubusercontent.com/nkopylov/tanscript-exploit-check/main/check-tanstack-exploit.sh | bash
```
Oppure clona ed esegui localmente:
```bash
git clone https://github.com/nkopylov/tanscript-exploit-check.git
cd tanscript-exploit-check
./check-tanstack-exploit.sh [project_dir ...]
```
---
## Cosa è successo
Questo controllore copre **due ondate** della campagna di attacco alla supply chain Mini Shai-Hulud di **TeamPCP**:
### Ondata 1: Compromissione CI/CD di TanStack (11 maggio 2026)
L'**11 maggio 2026** (19:20-19:26 UTC), un attaccante ha pubblicato **84 versioni dannose su 42 pacchetti npm `@tanstack/*`** in una finestra di 6 minuti. L'attacco ha colpito anche pacchetti di Mistral AI, UiPath, OpenSearch e altri — oltre 170 pacchetti in totale tra npm e PyPI.
**Non sono state rubate credenziali dei maintainer.** L'attaccante ha sfruttato la stessa catena di fiducia CI/CD tramite un attacco in 3 fasi:
1. **Exploit di `pull_request_target`** — Un fork GitHub usa e getta ha aperto una PR che eseguiva codice dell'attaccante nel contesto di sicurezza del repository di base
2. **Avvelenamento della cache di GitHub Actions** — Il codice del fork ha avvelenato la cache pnpm condivisa, che in seguito ha infettato i workflow di release legittimi
3. **Estrazione di token OIDC dalla memoria di processo** — Il codice malevolo ha estratto i token di pubblicazione npm direttamente dalla memoria del runner di GitHub Actions, producendo pacchetti con **attestazioni di provenienza SLSA Build Level 3 valide**
### Ondata 2: Compromissione dell'account npm "atool" (19 maggio 2026)
Il **19 maggio 2026** (01:39-02:06 UTC), l'account npm `atool` compromesso ([email protected]) ha pubblicato **637 versioni dannose su 314 pacchetti** in due ondate automatizzate. I target ad alto impatto includono:
- `size-sensor` (4.2M download al mese)
- `echarts-for-react` (3.8M download al mese)
- `@antv/scale` (2.2M download al mese)
- `timeago.js` (1.15M download al mese)
- 310+ pacchetti aggiuntivi `@antv/*` e altri
Questa ondata ha utilizzato un **payload basato su Bun** (`index.js` da 498KB) attivato tramite `"preinstall": "bun run index.js"`, con un payload di seconda fase nascosto in **commit impostori** pushati nel repository GitHub `antvis/G2` tramite lo sfruttamento della condivisione degli oggetti dei fork.
### Cosa fa il codice malevolo (entrambe le ondate)
Entrambe le ondate usano la stessa famiglia di toolkit "Mini Shai-Hulud":
- **Raccolta di credenziali**: 80+ variabili d'ambiente, catena AWS completa (env → config → IMDSv2 → ECS → Secrets Manager), PAT GitHub, token npm, chiavi SSH, token K8s, token Vault, password manager (1Password, Bitwarden, pass, gopass)
- **Persistenza**: demoni `gh-token-monitor` (Ondata 1) e `kitty-monitor` (Ondata 2) tramite LaunchAgent/systemd; hook in `.claude/settings.json` e `.vscode/tasks.json`
- **Esfiltrazione**: reti P2P (Ondata 1), GitHub Git Data API + HTTPS camuffato da trace OpenTelemetry (Ondata 2)
- **Abuso CI/CD**: iniezione nei workflow che scarica `toJSON(secrets)`, scambio di token OIDC npm
- **Dead-man's switch**: `rm -rf ~/` se il token GitHub viene revocato mentre il demone è attivo
- **C2 dead-drop** (Ondata 2): interroga l'API di ricerca commit di GitHub per la parola chiave `firedalazer`, comandi firmati RSA-PSS
## Cosa controlla questo script
| # | Controllo | Descrizione |
|---|-------|-------------|
| 1 | Dead-man's switch | Demoni di persistenza: `gh-token-monitor` (Ondata 1), `kitty-monitor` (Ondata 2) |
| 2 | Processi malevoli | Nomi di processo noti dell'attaccante (entrambe le ondate) |
| 3 | File payload | File malevoli noti per nome e hash SHA-256 (4 hash) |
| 4 | Hook di Claude Code | Hook iniettati in `.claude/settings.json` + euristica generica SessionStart |
| 5 | Task di VS Code | Task iniettati in `.vscode/tasks.json` + euristica generica `runOn: folderOpen` |
| 6 | GitHub Actions | `toJSON(secrets)` in **qualsiasi** workflow + avviso `pull_request_target` |
| 7 | Lockfile npm | Versioni di pacchetti compromesse nei lockfile |
| 8 | optionalDependencies | `@tanstack/setup` e `@antv/setup` malevoli + 4 SHA di commit impostori |
| 9 | Connessioni di rete | Connessioni attive verso l'infrastruttura C2 (5 domini/IP) |
| 10 | Cache DNS | Risoluzione precedente dei domini dell'attaccante (4 domini) |
| 11 | Branch Git | Pattern di denominazione dei branch dell'attaccante a tema Dune |
| 12 | Script di ciclo di vita | **Euristica:** `bun run` in preinstall/postinstall (pacchetti installati) |
| 13 | C2 dead-drop | Parola chiave `firedalazer` e marcatori "Shai-Hulud" nella cronologia git |
| 14 | Dipendenze GitHub | **Euristica:** dipendenze `github:` ancorate a uno SHA di commit in optionalDeps |
## Pacchetti interessati
### Ondata 1: TanStack (42 pacchetti)
Solo `@tanstack/router*` e `@tanstack/start*` sono stati colpiti. **NON colpiti:** `@tanstack/query*`, `@tanstack/table*`, `@tanstack/form*`, `@tanstack/virtual*`, `@tanstack/store`.
| Pacchetto | Versioni dannose | Prima versione sicura |
|---------|-------------------|--------------------|
| `@tanstack/react-router` | 1.169.5, 1.169.8 | 1.169.9 |
| `@tanstack/router-core` | 1.169.5, 1.169.8 | 1.169.9 |
| `@tanstack/vue-router` | 1.169.5, 1.169.8 | 1.169.9 |
| `@tanstack/solid-router` | 1.169.5, 1.169.8 | 1.169.9 |
| `@tanstack/react-start` | 1.167.68, 1.167.71 | 1.167.72 |
| `@tanstack/router-plugin` | 1.167.38, 1.167.41 | 1.167.42 |
Vedi la [advisory completa](https://github.com/TanStack/router/security/advisories/GHSA-g7cv-rxg3-hmpx) per tutti i 42 pacchetti.
### Ondata 2: account atool (314 pacchetti)
Tutti i pacchetti pubblicati dall'utente npm `atool` ([email protected]) hanno ricevuto versioni dannose il 19 maggio 2026. I pacchetti ad alto impatto includono:
| Pacchetto | Download mensili |
|---------|------------------|
| `size-sensor` | 4.2M |
| `echarts-for-react` | 3.8M |
| `@antv/scale` | 2.2M |
| `timeago.js` | 1.15M |
Più altri 310+ pacchetti principalmente nell'ambito `@antv/*` (`@antv/g2`, `@antv/g6`, `@antv/l7`, `@antv/s2`, `@antv/x6`, `@antv/f2`, ecc.), `ai-figure`, `timeago-react`, `jest-canvas-mock`, `jest-date-mock` e altri.
Vedi l'[analisi SafeDep](https://safedep.io/mini-shai-hulud-strikes-again-314-npm-packages-compromised/) per l'elenco completo.
## Rimedio (se compromessi)
> **CRITICO: disattiva il dead-man's switch PRIMA di revocare qualsiasi token.** Il malware cancella `$HOME` se i token vengono revocati mentre il demone è attivo.
1. Termina i demoni di persistenza (`gh-token-monitor` E `kitty-monitor`) e rimuovi i servizi LaunchAgent/systemd
2. Rimuovi i file di persistenza (`.claude/router_runtime.js`, `.vscode/setup.mjs`, `~/.local/share/kitty/cat.py`, `/var/tmp/.gh_update_state`, ecc.)
3. Elimina `node_modules` e i lockfile, reinstalla con `--ignore-scripts`
4. Ruota **TUTTE** le credenziali (npm, GitHub, AWS, GCP, chiavi SSH, token Vault, token dei password manager, ecc.)
5. Blocca i domini dell'attaccante a livello DNS/firewall (`api.masscan.cloud`, `filev2.getsession.org`, `git-tanstack.com`, `t.m-kosche.com`)
6. Esegui un audit dei log dei provider cloud per l'11-19 maggio 2026
## Annunci ufficiali e riferimenti
### Ondata 1: TanStack (11 maggio)
- **CVE-2026-45321** (CVSS 9.6 Critico) — [Record CVE](https://www.cve.org/CVERecord?id=CVE-2026-45321)
- **GHSA-g7cv-rxg3-hmpx** — [Advisory GitHub](https://github.com/TanStack/router/security/advisories/GHSA-g7cv-rxg3-hmpx)
- **Postmortem di TanStack** — [tanstack.com/blog/npm-supply-chain-compromise-postmortem](https://tanstack.com/blog/npm-supply-chain-compromise-postmortem)
- **Follow-up di hardening di TanStack** — [tanstack.com/blog/incident-followup](https://tanstack.com/blog/incident-followup)
- **Issue di monitoraggio GitHub** — [TanStack/router#7383](https://github.com/TanStack/router/issues/7383)
### Ondata 2: compromissione dell'account atool (19 maggio)
- **Analisi SafeDep** — [safedep.io/mini-shai-hulud-strikes-again-314-npm-packages-compromised/](https://safedep.io/mini-shai-hulud-strikes-again-314-npm-packages-compromised/)
### Analisi dei ricercatori di sicurezza
- [Socket.dev](https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack)
- [Snyk](https://snyk.io/blog/tanstack-npm-packages-compromised/)
- [StepSecurity](https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem) (scopritori originali)
- [Wiz](https://www.wiz.io/blog/mini-shai-hulud-strikes-again-tanstack-more-npm-packages-compromised)
- [Orca Security](https://orca.security/resources/blog/tanstack-npm-supply-chain-worm/)
- [SecurityWeek](https://www.securityweek.com/tanstack-mistral-ai-uipath-hit-in-fresh-supply-chain-attack/)
## Prompt di hardening per agenti di coding AI
Copia-incolla questi prompt nel tuo agente di coding AI (Claude Code, Cursor, Cline/OpenClaw, Windsurf, Hermes, ecc.) per indurire il tuo progetto contro attacchi alla supply chain come questo.
### Prompt 1: ritardo di pubblicazione npm (quarantena delle nuove versioni)
> Indurisci la configurazione npm di questo progetto contro gli attacchi alla supply chain. Fai quanto segue:
>
> 1. **Blocca le versioni esatte**: rimuovi tutti i prefissi `^` e `~` da ogni dipendenza in `package.json` in modo che `npm install` non scarichi mai silenziosamente una versione appena pubblicata.
>
> 2. **Disabilita gli script postinstall per impostazione predefinita**: aggiungi `ignore-scripts=true` a `.npmrc`. Poi aggiungi uno script `"preinstall"` esplicito in `package.json` che esegua solo gli script di ciclo di vita noti come sicuri di cui questo progetto ha effettivamente bisogno (se presenti).
>
> 3. **Imponi installazioni basate solo su lockfile in CI**: assicurati che la CI usi `npm ci` (non `npm install`). Se c'è un file di configurazione CI, verificalo. In caso contrario, annotalo come passaggio manuale.
>
> 4. **Aggiungi la verifica della provenienza**: aggiungi `npm audit signatures` come passaggio nella pipeline CI e come hook git pre-push.
>
> 5. **Crea uno script di policy di aggiornamento**: crea un `scripts/safe-update.sh` che:
> - Prende un nome di pacchetto come argomento
> - Controlla quando è stata pubblicata l'ultima versione (`npm view <pkg> time --json`)
> - Rifiuta di aggiornare se la versione ha meno di 3 giorni
> - Se più vecchia di 3 giorni, esegue `npm install <pkg>@latest --save-exact`
> - Stampa un riepilogo di cosa è cambiato
>
> Non modificare alcun codice applicativo. Tocca solo file di configurazione, `.npmrc`, script di `package.json` e configurazione CI.
### Prompt 2: indurisci la configurazione dell'agente AI
> Esegui un audit e indurisci la configurazione dell'agente di coding AI di questo progetto contro gli attacchi di iniezione nella supply chain (come la campagna TanStack/Mini Shai-Hulud che ha iniettato hook malevoli in `.claude/settings.json` e `.vscode/tasks.json`). Fai quanto segue:
>
> **Claude Code (`.claude/`)**:
> 1. Rivedi `.claude/settings.json` e `.claude/settings.local.json` per eventuali voci `hooks` che eseguono comandi shell. Segnala qualsiasi cosa che esegua file `.js`, `.mjs` o `.sh` — soprattutto dall'interno di `.claude/`, `.vscode/` o `node_modules/`.
> 2. Rimuovi qualsiasi hook che non riesci a ricondurre a uno scopo legittimo creato dall'utente.
> 3. Aggiungi una regola `.gitignore` per impedire che `.claude/settings.local.json` venga committato (dovrebbe rimanere locale).
>
> **VS Code (`.vscode/`)**:
> 1. Rivedi `.vscode/tasks.json` e `.vscode/launch.json` per task che eseguono script o binari inaspettati.
> 2. Rimuovi qualsiasi voce di task che faccia riferimento a file come `setup.mjs`, `router_runtime.js` o altri nomi che non appartengono a questo progetto.
> 3. Controlla `.vscode/extensions.json` per estensioni che non riconosci.
>
> **Cursor (`.cursor/`)**:
> 1. Rivedi `.cursor/settings.json` e qualsiasi file di regole per comandi o hook iniettati.
> 2. Stessi controlli di VS Code qui sopra — Cursor eredita la configurazione `.vscode/`.
>
> **Generale**:
> 1. Controlla la presenza di script `preinstall`, `postinstall`, `prepare` o `prestart` in `package.json` che non hai scritto tu. Segnala quelli sospetti.
> 2. Controlla `.github/workflows/` per qualsiasi workflow che usi `pull_request_target` — segnalalo come rischio per la sicurezza con un commento che spieghi il perché.
> 3. Assicurati che `.gitignore` escluda i file di sessione degli agenti che potrebbero far trapelare credenziali (`.claude/projects/`, `.cursor/logs/`, ecc.).
>
> Riporta cosa hai trovato e cosa hai modificato. Non modificare il codice applicativo.
### Prompt 3: hardening di GitHub Actions
> Esegui un audit e indurisci la configurazione di GitHub Actions in questo repository contro gli attacchi alla supply chain CI/CD. Fai quanto segue:
>
> 1. **Rimuovi o rifattorizza qualsiasi trigger `pull_request_target`** — questi eseguono codice di workflow nel contesto del repository di base con accesso ai segreti, anche quando attivati da un fork. Sostituiscili con `pull_request` + un workflow separato con approvazione se necessario.
>
> 2. **Ancora tutte le azioni di terze parti a SHA di commit completi** (non tag o branch). Ad esempio, sostituisci `actions/checkout@v4` con `actions/checkout@<full-sha>`. Aggiungi un commento con il tag per leggibilità.
>
> 3. **Applica permessi con privilegi minimi** a ogni workflow. Aggiungi blocchi `permissions:` espliciti. La maggior parte dei workflow ha bisogno solo di `contents: read`. I workflow di pubblicazione necessitano di `id-token: write` — e nient'altro.
>
> 4. **Limita l'ambito della cache**: se usi `actions/cache`, assicurati che le chiavi di cache siano limitate al branch per prevenire l'avvelenamento tra branch. Aggiungi `restore-keys` con cautela — non ripristinare cache da branch non attendibili.
>
> 5. **Aggiungi StepSecurity Harden-Runner** come primo passaggio in ogni job: `step-security/harden-runner@v2` con `egress-policy: audit` (o `block` se conosci i tuoi endpoint consentiti).
>
> 6. **Controlla la presenza di segreti nei log dei workflow**: assicurati che nessun passaggio dei workflow stampi `${{ secrets.* }}` o `${{ toJSON(secrets) }}` su stdout.
>
> Riporta tutte le modifiche. Non modificare il codice applicativo.
## Licenza
MIT