Skip to main content

« Un Mini Shai-Hulud est apparu » : un voleur basé sur Bun cible les packages npm SAP @cap-js et mbt

Écrit par

29 avril 2026

0 minutes de lecture

Le 29 avril 2026, des attaquants ont publié des versions malveillantes de quatre packages npm de l’écosystème de développement SAP : mbt, @cap-js/db-service, @cap-js/sqlite et @cap-js/postgres. Chaque version compromise inclut un hook preinstall qui télécharge le runtime JavaScript Bun depuis GitHub Releases et l’utilise pour exécuter un voleur d’identifiants obfusqué d’environ 11,6 Mo.

La charge utile s’identifie avec une description codée en dur, « A Mini Shai-Hulud has Appeared », qui apparaît en temps réel dans les résultats de recherche publics de GitHub, à mesure que les machines de développeurs compromises créent des dépôts de dépôt mort sur leurs propres comptes. La campagne reprend le nom Shai-Hulud (les dépôts de dépôt mort portent ce nom) et inclut un code fonctionnel de propagation automatique via npm, selon la désobfuscation complète de StepSecurity. À la date de publication, seuls les quatre packages initialement compromis ont été observés dans la nature ; l’analyse technique et le compte npm compromis à l’origine des premières publications sont détaillés ci-dessous.

Snyk a publié des avis pour les quatre versions compromises. Les versions concernées sont signalées par snyk test et répertoriées sur la page Base de données de sécurité Snyk de chaque package.

Packages concernés et avis Snyk

Package

Version compromise

Avis Snyk

Téléchargements hebdomadaires approx.

mbt

1.2.48

~52 000

@cap-js/db-service

2.10.1

~260 000

@cap-js/sqlite

2.2.2

~250 000

@cap-js/postgres

2.2.2

~10 000

Nombre de téléchargements hebdomadaires extrait de l’API publique des téléchargements du registre npm pour la semaine précédant la compromission (du 22 au 28 avril 2026). Les quatre packages font partie de la chaîne d’outils SAP Cloud Application Programming Model. mbt est le Cloud MTA Build Tool distribué via npm et utilisé pour créer des archives de déploiement pour les applications cloud SAP. Les packages @cap-js/* fournissent des services de base de données pour les applications CAP.

Les versions malveillantes ont été publiées dans un intervalle restreint le 29 avril 2026, toutes en UTC. Les horodatages ont été vérifiés directement auprès de registry.npmjs.org et de l’API GitHub :

  • 09:55:25 : publication de mbt@1.2.48 depuis le compte npm cloudmtabot.

  • 10:01:07 : apparition sur GitHub du premier dépôt de dépôt mort d’une victime (gruposbftechrecruiter/siridar-navigator-935, d’après les horodatages de l’API GitHub).

  • 11:25:47 : publication de @cap-js/sqlite@2.2.2.

  • 12:03 to 12:04 : StepSecurity dépose des signalements de divulgation sur cap-js/cds-dbs#1588 et SAP/cloud-mta-build-tool#1224. Un troisième signalement indépendant, SAP/open-ux-tools#4616, est déposé par longieirl à 14:02.

  • 12:14:00 : publication de @cap-js/postgres@2.2.2 et @cap-js/db-service@2.10.1.

  • 13:31 : le responsable de maintenance de cap-js chgeo répond : « Merci de nous l’avoir signalé. Nous allons nettoyer les packages en priorité et enquêter sur les causes profondes. »

  • 13:46 : SAP publie des versions saines après l’incident via l’éditeur de confiance OIDC GitHub Actions cap-npm : @cap-js/db-service@2.11.0, @cap-js/sqlite@2.4.0 et @cap-js/postgres@2.3.0 (avec une mise à jour coordonnée vers @cap-js/hana@2.8.0).

  • 14:02:50 : l’ingénieur SAP patricebender dépose la PR cap-js/cds-dbs PR #1592, qui conditionne la publication npm à une approbation manuelle dans un environnement. Elle reprend textuellement la déclaration sur la cause profonde citée ci-dessus.

  • 14:24 : le contributeur de cloud-mta-build-tool kbarnold répond : « Merci pour le signalement. Nous nous en occupons en priorité. »

@cap-js/sqlite@2.2.2 a été retiré de npm peu après sa détection. Les autres versions malveillantes comportent des messages de dépréciation npm : mbt@1.2.48 est signalé par « SÉCURITÉ : cette version contient du code malveillant. Ne l’utilisez pas. », tandis que les versions malveillantes @cap-js/* affichent « NE PAS UTILISER. Cette version contient du contenu inconnu. ». Point crucial : au moment de la rédaction, mbt@1.2.48 était toujours la version indiquée par le dist-tag latest pour mbt, et aucune version corrigée de mbt n’avait encore été publiée. Une simple commande npm install mbt installait donc toujours l’archive malveillante. Au moment de la publication, aucun enregistrement CVE, GHSA ou OSV n’avait été attribué à l’un des quatre packages ; les seules sources publiques faisant autorité sont les quatre billets des éditeurs cités dans cet article et les trois signalements de divulgation sur GitHub.

Pourquoi cette attaque est appelée « Mini » Shai-Hulud (et ce qui la distingue vraiment)

Le nom Shai-Hulud a déjà été utilisé à deux reprises pour des incidents touchant la chaîne d’approvisionnement npm. La campagne originale Shai-Hulud, en septembre 2025, a ciblé @ctrl/tinycolor, ngx-bootstrap, ng2-file-upload et de nombreux packages dépendants (le rapport de Snyk sur cette vulnérabilité zero-day en a suivi le déroulement). La vague suivante, SHA1-Hulud, en novembre 2025, s’est étendue à plus de 600 packages différents, notamment des versions de Zapier, PostHog et Postman. L’équipe Securelist de Kaspersky a publié des analyses techniques indépendantes sur ces deux vagues (nom de détection HEUR:Worm.Script.Shulud.gen) à l’adresse securelist.com/shai-hulud-worm-infects-500-npm-packages et à l’adresse securelist.com/shai-hulud-2-0.

A Mini Shai-Hulud Has Appeared": Bun-Based Stealer Hits SAP @cap-js and mbt npm Packages

Attaque NPM Shai-Hulud : remédiation avec Snyk (courte démonstration expliquant comment identifier et corriger les dépendances affectées par Shai-Hulud dans vos projets avec l’interface CLI et les pages de conseils de Snyk).

Les deux campagnes précédentes présentaient un comportement de ver : la charge utile récupérait le jeton npm d’une victime, puis l’utilisait pour se publier dans tous les autres packages sur lesquels ce jeton disposait de droits d’écriture. L’attention du public a suivi cette évolution : l’article Wikipédia sur le ver des sables de Dune a atteint un pic de 2 772 vues pendant la divulgation de SHA1-Hulud en novembre 2025 (son record quotidien sur une période de 16 mois, soit environ quatre fois sa moyenne), et l’article Wikipédia plus général sur les « attaques de la chaîne d’approvisionnement » a atteint sa moyenne mensuelle la plus élevée jamais enregistrée en avril 2026, le mois de Mini Shai-Hulud (310 vues par jour, selon l’API REST de Wikimedia).

La campagne du 29 avril reprend l’image de marque Shai-Hulud (les dépôts de dépôt mort portent la chaîne de description) ; toutefois, les éléments publics disponibles à ce jour indiquent un ensemble de comportements plus restreint :

  • Vol d’identifiants : observé et détaillé par plusieurs chercheurs.

  • Injection de mécanismes de persistance dans les configurations des outils de développement : une nouveauté détaillée ci-dessous.

  • Publication automatique de packages npm : le code est présent et fonctionnel, selon la désobfuscation statique de StepSecurity. La charge utile récupère les jetons npm à l’aide de l’expression régulière /npm_[A-Za-z0-9]{36,}/g, vérifie chacun d’eux auprès de registry.npmjs.org/-/npm/v1/tokens (en filtrant ceux pour lesquels bypass_2fa: true et disposant de droits d’écriture au niveau de l’organisation), énumère les packages accessibles, insère setup.mjs et execution.js dans une copie de l’archive, puis publie directement sur le registre npm par une requête PUT, sans lancer l’interface CLI npm. À la date de publication, aucun cinquième package en dehors des quatre premiers n’a été observé dans la nature avec la charge utile malveillante ; la capacité du ver à se propager est toutefois un fait avéré, et non une simple déduction.

  • Piraterie du pipeline CI comme vecteur d’accès : la déclaration officielle de SAP dans la PR #1592 déposée par patricebender sur cap-js/cds-dbs (le même jour à 14:02 UTC) indique : « Le 29 avril 2026, une attaque de la chaîne d’approvisionnement a compromis le dépôt : un acteur non autorisé a poussé des commits malveillants qui ont détourné le workflow de publication et déclenché des publications npm non autorisées. L’attaquant a pu publier des packages compromis, car le workflow disposait des autorisations de publication sans exiger d’approbation manuelle. » La solution consiste à soumettre la publication npm à une validation dans un environnement. D’après les données du registre npm, les quatre versions malveillantes ont été publiées depuis le compte cloudmtabot (le responsable légitime de mbt) ; les versions saines publiées par SAP après l’incident, à 13:46 UTC, l’ont été via l’éditeur de confiance OIDC GitHub Actions cap-npm, et non par cloudmtabot. Le compte cloudmtabot lui-même a depuis été suspendu sur npm. La compromission des identifiants d’un responsable de maintenance est un vecteur d’entrée récurrent pour ce type d’incident, mais la déclaration de SAP désigne précisément l’absence de validation dans le workflow comme cause structurelle.

Le vol d’identifiants permet la réplication automatique sur npm, mais les activités immédiatement observées sont l’exfiltration et un nouveau mécanisme de persistance. Dans les deux cas, les priorités de défense restent les mêmes : vérifier le fichier de verrouillage, renouveler les identifiants et définir une politique pour les scripts de cycle de vie.

Comment fonctionne l’attaque

Le mode opératoire est le même pour les quatre packages : l’archive malveillante conserve les fichiers du package légitime sans les modifier (l’interface CLI fonctionne donc toujours après l’installation) et ajoute deux nouveaux fichiers : setup.mjs (un chargeur Bun en texte brut de 4,5 Ko, identique octet par octet dans les quatre packages) et execution.js (une charge utile obfusquée de précisément 11 678 349 octets, dont les empreintes diffèrent entre mbt et les packages @cap-js/*). Pour mbt uniquement, le fichier malveillant package.json ajoute également trois dépendances (axios, tar et unzip-stream) absentes de la version saine précédente. Les trois packages cap-js ont uniquement ajouté le hook preinstall à leur fichier package.json existant.

Télécharger un petit chargeur pendant l’installation pour récupérer un runtime et une charge utile bien plus volumineux est une méthode que Snyk a observée ailleurs cette année, notamment lors de l’axios, où le hook d’installation récupérait un binaire natif distribué via une dépendance distincte.

Pour mbt, voici les différences entre la version 1.2.47 (saine) et la version 1.2.48 (malveillante) :

// 1.2.47: no scripts block
// 1.2.48:
{
  "scripts": {
    "preinstall": "node setup.mjs"
  },
  "dependencies": {
    "axios": "^1.13.5",
    "tar": "^7.5.7",
    "unzip-stream": "^0.3.4"
  }
}

preinstall s’exécute avant que npm n’affiche quoi que ce soit à l’utilisateur et avant qu’une éventuelle politique --ignore-scripts puisse intervenir si l’option n’est pas définie. Le hook exécute setup.mjs, qui :

  1. Détecte la plateforme et l’architecture (y compris la détection d’Alpine/musl sous Linux).

  2. Vérifie si bun est déjà présent dans le PATH à l’aide de hasCommand("bun"). Si c’est le cas, il ignore l’étape de téléchargement et utilise le binaire existant. Sinon, il télécharge Bun 1.3.13 depuis GitHub Releases (en suivant les redirections HTTP sans vérifier la destination, selon l’analyse de Socket).

  3. Extrait le binaire Bun dans un répertoire temporaire s’il a été téléchargé.

  4. Lance bun execution.js pour exécuter la charge utile obfusquée.

Une fois bun execution.js lancé, la charge utile passe par deux couches d’obfuscation : une rotation de table de chaînes à la manière d’obfuscator.io (48 370 entrées décodées à l’aide d’un alphabet base64 non standard et protégées par une somme de contrôle au démarrage) et un chiffrement personnalisé que StepSecurity a baptisé « ctf-scramble-v2 », avec une clé maîtresse dérivée par PBKDF2. Les deux couches ont été entièrement reconstituées par analyse statique. Le code d’exécution déchiffré est du JavaScript exécuté par Bun (sans WASM intégré ni code natif ; la charge utile utilise des API natives de Bun telles que Bun.gunzipSync() et Bun.main).

La désobfuscation statique de StepSecurity décrit les comportements suivants de la charge utile :

  • Récupère les identifiants locaux, les jetons GitHub et npm, les secrets GitHub Actions et ceux des services cloud AWS, Azure, GCP et Kubernetes, les jetons des interfaces CLI de gestionnaires de mots de passe (1Password, Bitwarden, LastPass), ~/.claude.json et les configurations des serveurs MCP, les variables d’environnement correspondant aux motifs KEY/TOKEN/SECRET/PASSWORD, ainsi que les clés de portefeuilles crypto présentes sur l’hôte. La charge utile interroge également le service de métadonnées d’instance AWS (169.254.169.254) lorsqu’il est accessible.

  • Sur les runners CI Linux, il lance un processus enfant Python qui lit /proc/{pid}/mem du processus Runner.Worker de GitHub Actions pour extraire les secrets en clair directement de la mémoire du runner.

  • Sous Windows, il invoque PowerShell avec -ExecutionPolicy Bypass.

  • Il sérialise les données volées au format JSON, les compresse avec gzip, les chiffre avec AES-256-GCM (clé de 32 octets, IV de 12 octets), puis protège la clé AES avec RSA-OAEP-SHA256 à l'aide d'une clé publique RSA-4096 intégrée (stockée sous forme de PEM gzip+base64 à l'offset 9,429,992 du fichier execution.js, puis décompressée à l'exécution via Bun.gunzipSync()). Ainsi, les défenseurs qui découvrent le dépôt de dépôt mort peuvent voir qu'un vol a eu lieu, mais ne peuvent pas déterminer ce qui a été dérobé. En pratique, tout identifiant auquel le processus a pu accéder doit être considéré comme compromis.

  • Il crée sur le compte GitHub de la victime un dépôt public dont le nom est composé de caractères aléatoires et dont la description est « A Mini Shai-Hulud has Appeared », puis y enregistre le texte chiffré comme dépôt mort.

  • Il vérifie les paramètres régionaux du système via l'API JavaScript Intl et les variables d'environnement POSIX (LC_ALL, LC_MESSAGES, LANGUAGE, LANG). Si les paramètres régionaux indiquent le russe (ru), la charge utile journalise "Exiting as russian language detected!" et s'arrête. Ces vérifications d'exclusion des pays de la CEI concordent avec le comportement documenté des opérations cybercriminelles dans ces régions.

Le mécanisme de persistance

Que la campagne soit qualifiée de ver ou non, le mécanisme de persistance est l'élément le plus novateur décrit dans les rapports publics.

Selon StepSecurity, la charge utile utilise trois mécanismes de persistance et de réexécution :

  • Injection dans la configuration des outils de développement. Dans chaque dépôt GitHub auquel le jeton volé peut écrire, la charge utile ajoute un fichier .claude/settings.json qui utilise le hook SessionStart de Claude Code pour réexécuter la charge utile à chaque démarrage d'une session Claude Code par un développeur, ainsi qu'un fichier .vscode/tasks.json avec "runOn": "folderOpen", qui se déclenche à l'ouverture du projet dans VS Code. Ces fichiers injectés sont enregistrés sous l'identité claude@users.noreply.github.com, avec le message "chore: update dependencies", ce qui peut les faire passer pour des commits d'automatisation courants lors de la revue des PR.

  • Injection dans le workflow GitHub Actions. Lorsque le jeton volé dispose de la portée workflow, la charge utile crée une branche usurpant un nom de domaine (dependabout/github_actions/format/setup-formatter, notez le t manquant) et y ajoute .github/workflows/format-check.yml, en usurpant le compte de service Dependabot (dependabot[bot]@users.noreply.github.com, avec le message de commit "Add formatter workflow"). Le workflow injecté utilise ${{ toJSON(secrets) }} pour extraire tous les secrets du dépôt dans un artefact de compilation nommé format-results.txt.

  • Exécution en tant que démon sur les machines des développeurs. Sur les hôtes hors CI, la charge utile se lance en processus d'arrière-plan détaché, avec la variable d'environnement __DAEMONIZED=1, puis le processus parent se termine sans erreur apparente : npm install rend ainsi la main à l'utilisateur sans message d'erreur visible. Le processus enfant détaché continue de fonctionner sans lien de parenté clair.

Cela élargit l'ensemble des vecteurs de persistance observés lors de l'installation dans les campagnes visant la chaîne d'approvisionnement npm : les fichiers de configuration des agents de programmation IA s'ajoutent aux hooks du cycle de vie de package.json, aux workflows CI et aux manifestes de plugins IDE.

Les attaques ciblant la surface d'exposition des configurations d'agents IA s'inscrivent dans des précédents documentés : elles ne sont pas inédites. Le ticket VSCode #309406 de Microsoft, portant sur le vecteur tasks.json runOn: folderOpen, a été déposé seize jours plus tôt et clos avec le statut « By Design » (la confiance accordée à l'espace de travail est considérée comme une mesure d'atténuation suffisante, bien que cette vérification ne couvre pas les commits ajoutés à des dépôts déjà approuvés). Le ticket claude-code #49778 d'Anthropic, concernant le hook SessionStart, a été déposé douze jours plus tôt et reste ouvert sans réponse d'Anthropic. Il cite un précédent réel dans l'audit de la chaîne d'approvisionnement de Cozempic. En mars 2026, la compromission de l'agent IA Trivy (CVE-2026-28353) est allée plus loin : des jetons volés ont servi à publier une extension VS Code piégée ciblant cinq agents de programmation IA différents. Snyk a également analysé séparément ce même croisement dans son article sur Clinejection. Mini Shai-Hulud est un nouveau cas dans cette tendance, pas le premier.

Indicateurs de compromission

Cette liste est une synthèse des rapports publics de StepSecurity, Aikido, Socket et SafeDep. Consultez ces rapports pour obtenir la liste complète des IOC et les détails de l'analyse forensique. Chaque version malveillante reste consultable sous forme d'enregistrement immuable dans le registre npm aux adresses registry.npmjs.org/mbt/1.2.48, registry.npmjs.org/@cap-js/sqlite/2.2.2, registry.npmjs.org/@cap-js/postgres/2.2.2 et registry.npmjs.org/@cap-js/db-service/2.10.1 ; l'horodatage de publication et la signature "preinstall": "node setup.mjs" sont conservés dans chaque enregistrement.

Compromised npm artifacts
  mbt@1.2.48                       shasum 0af7415d65753f6aede8c9c0f39be478666b9c12
  @cap-js/db-service@2.10.1        shasum 4b04304f6d51392e3f43856c94ca95800518a694
  @cap-js/sqlite@2.2.2             shasum 7b6a28e92149637e5d7c7f4a2d3e54acd507c929
  @cap-js/postgres@2.2.2           shasum e80824a19f48d778a746571bb15279b5679fd61c

Compromised npm publisher account
  cloudmtabot (used to publish all four malicious versions)

Files added to the compromised tarballs
  setup.mjs       ~4.5 KB plaintext Bun loader, byte-identical
                   across all four packages
  execution.js    11,678,349 bytes obfuscated payload, hash
                   differs per package

File hashes (SHA-256, per StepSecurity)
  setup.mjs (all packages)
    4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34
  execution.js (mbt@1.2.48)
    80a3d2877813968ef847ae73b5eeeb70b9435254e74d7f07d8cf4057f0a710ac
  execution.js (@cap-js/sqlite@2.2.2)
    6f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95
  Embedded /proc/mem dumper
    29ac906c8bd801dfe1cb39596197df49f80fff2270b3e7fbab52278c24e4f1a7

In-payload indicators (recovered by StepSecurity static analysis)
  Custom cipher salt              ctf-scramble-v2
  PBKDF2 input key                5012caa5847ae9261dfa16f91417042f367d6bed149c3b8af7a50b203a093007
  Derived master key              fd4b0f07b27e8f41bc70b8e2b79d168fb3fe80d7e0b37f43c506136a3418b44d
  CIS evasion log string          Exiting as russian language detected!
  Daemonization env var           __DAEMONIZED
  GitHub PAT regex                /gh[op]_[A-Za-z0-9]{36}/g
  npm token regex                 /npm_[A-Za-z0-9]{36,}/g

Network and runtime indicators
  - Outbound request to github.com/oven-sh/bun/releases/download/bun-v1.3.13/{asset}.zip
    where {asset} is one of:
      bun-linux-aarch64
      bun-linux-x64-baseline
      bun-linux-x64-musl-baseline
      bun-darwin-aarch64
      bun-darwin-x64
      bun-windows-aarch64
      bun-windows-x64-baseline
    (skipped if `bun` is already on PATH)
  - Process chain during install:
    node setup.mjs -> bun execution.js
  - Linux CI runners: child Python process reading
    /proc/{pid}/mem of Runner.Worker
  - Windows: powershell -ExecutionPolicy Bypass
  - api.github.com calls:
    POST /user/repos               (dead-drop repo creation)
    GET  /search/commits?q=OhNoWhatsGoingOnWithGitHub
                                   (P2P token dead-drop search)
  - Direct PUT to registry.npmjs.org during self-propagation
    (no npm CLI involvement)
  - Cloud metadata reads:
    http://169.254.169.254          (AWS/Azure IMDS)
    http://169.254.170.2            (ECS task metadata)
    http://[fd00:ec2::254]          (AWS IMDSv2 IPv6)

GitHub-side indicators
  - New public repositories on developer accounts with the
    description string "A Mini Shai-Hulud has Appeared"
  - Repository names follow a Dune-themed pattern, regex:
    (sardaukar|mentat|fremen|atreides|harkonnen|gesserit|
     prescient|fedaykin|tleilaxu|siridar|kanly|sayyadina|
     ghola|powindah|prana|kralizec)-(sandworm|ornithopter|
     heighliner|stillsuit|lasgun|sietch|melange|thumper|
     navigator|fedaykin|futar|slig|phibian|laza|cogitor|
     ghola)-\d{1,3}
  - Commits authored by claude@users.noreply.github.com
    with the message "chore: update dependencies"
  - New or modified .claude/settings.json files containing
    a SessionStart hook
  - New or modified .vscode/tasks.json with a task using
    "runOn": "folderOpen"
  - P2P token dead-drop commits referencing the string
    "OhNoWhatsGoingOnWithGitHub" (used by the malware to
    locate base64-encoded tokens left by other victims)
  - Typosquatted Dependabot branch:
    dependabout/github_actions/format/setup-formatter
  - Injected workflow file .github/workflows/format-check.yml
    using the expression toJSON(secrets), authored by
    dependabot[bot]@users.noreply.github.com with commit
    message "Add formatter workflow", uploading artifact
    "format-results.txt"

Recherches GitHub en direct sur les deux chaînes distinctives :

Chaque dépôt mort contient un unique fichier README.md et un ou plusieurs fichiers de la forme results/results-<unix-ms>-<counter>.json. L'examen direct d'un dépôt actif de victime par des chercheurs externes a confirmé le format du fichier :

{"envelope": "<base64 AES-256-GCM ciphertext>", "key": "<base64 RSA-4096 wrapped session key>"}

Comme la clé de chiffrement est la clé publique RSA-4096 de l'attaquant, les défenseurs ne peuvent pas lire le contenu, même s'ils ont un accès complet au compte GitHub de la victime.

Que faire

L'ampleur de l'impact dépend du fait que vos pipelines de compilation ou les machines de vos développeurs aient exécuté npm install avec l'une des quatre versions touchées pendant la période d'exposition (environ de 10 h à 14 h UTC le 29 avril 2026, ainsi que pendant toute période où les versions dépréciées restent résolubles).

Vérifiez vos installations. Recherchez les versions touchées dans vos fichiers de verrouillage et vérifiez la résolution transitive : @cap-js/sqlite@2.2.2 déclare @cap-js/db-service@^2.10.0 comme dépendance. Une installation propre de @cap-js/sqlite avec une plage de versions résoluble peut donc récupérer @cap-js/db-service@2.10.1 (la version malveillante) en tant que dépendance transitive, même si personne ne l'a explicitement répertoriée.

# in any project root
rg -n '"mbt"|"@cap-js/db-service"|"@cap-js/sqlite"|"@cap-js/postgres"' \
   package-lock.json npm-shrinkwrap.json yarn.lock pnpm-lock.yaml 2>/dev/null

Pour les clients de Snyk, snyk test et snyk monitor détecteront les versions malveillantes à l'aide des quatre avis de sécurité indiqués ci-dessus. Les pages de la base de données de sécurité Snyk consacrées à mbt, @cap-js/db-service, @cap-js/sqlite et @cap-js/postgres rendent également compte de cet incident.

Si une version compromise a été installée :

  • Considérez comme exposés tous les identifiants accessibles depuis cette machine ou ce pipeline. Le chiffrement RSA contrôlé par l'attaquant empêche les défenseurs de lire le contenu du dépôt mort pour confirmer l'étendue de l'attaque ; il faut donc adopter une approche prudente pour la rotation. Parmi les 134 modèles de chemin de fichier récupérés par StepSecurity dans la charge utile, on trouve au minimum : les jetons de publication npm (priorité absolue, car ils permettent la propagation du ver à d'autres packages maintenus par un développeur), les jetons d'accès personnels GitHub et les autorisations OAuth, les identifiants AWS/Azure/GCP et tous les rôles pouvant être assumés depuis la machine touchée, les fichiers kubeconfig Kubernetes (~/.kube/config, YAML k3s, jetons de compte de service dans les pods), les configurations Docker (~/.docker/config.json), les identifiants Terraform Cloud (~/.terraform.d/credentials.tfrc.json), la configuration Helm, les clés SSH (~/.ssh/id*, config, known_hosts, clés d'hôte dans /etc/ssh/), les jetons des interfaces en ligne de commande de gestionnaires de mots de passe (op pour 1Password, bw pour Bitwarden, LastPass), .npmrc / .pypirc / .yarnrc, .gitconfig et .git-credentials, les fichiers d'historique du shell, les variables d'environnement et les fichiers .env* correspondant aux modèles *_TOKEN, *_KEY, *_SECRET ou *_PASSWORD, ~/.claude.json et toutes les configurations de serveurs MCP (y compris celles de Kiro dans ~/.kiro/settings/mcp.json), les données de session des applications de messagerie (Signal, cookies Slack, Discord, Telegram, Element, Pidgin), les configurations VPN (NordVPN, ProtonVPN, OpenVPN, etc.), les listes de serveurs FileZilla, les configurations Ansible et les clés de portefeuilles crypto pour Bitcoin, Ethereum, Monero, Dash, Zcash, Dogecoin, Litecoin, Electrum, Exodus, Ledger Live et Atomic. La charge utile lit également les métadonnées d'instance AWS (169.254.169.254, 169.254.170.2, fd00:ec2::254) et les métadonnées des tâches ECS. Tous les rôles IAM accessibles via ces points de terminaison doivent donc être considérés comme exposés.

  • Vérifiez l'exposition des secrets GitHub Actions. La technique d'extraction de /proc/{pid}/mem lit l'ensemble de l'espace d'adressage accessible en lecture de Runner.Worker : tout secret utilisé dans le workflow jusque-là est donc concerné, même s'il n'est pas directement référencé par l'étape d'installation. Les runners hébergés par GitHub n'empêchent pas cet accès par défaut ; sa détection nécessite un agent de sécurité côté runner, comme StepSecurity Harden-Runner.

  • Passez votre organisation GitHub au crible des IOC figurant dans le bloc de code ci-dessus : dépôts morts dont le nom suit le modèle inspiré de Dune et qui portent la description « Mini Shai-Hulud », signature d'auteur claude@users.noreply.github.com, usurpation de dependabot[bot]@users.noreply.github.com dans une branche dependabout/..., workflow injecté .github/workflows/format-check.yml qui exfiltre toJSON(secrets) dans un artefact format-results.txt, chaîne de commit P2P de dépôt mort de jetons OhNoWhatsGoingOnWithGitHub, et ajouts inattendus à .claude/settings.json ou .vscode/tasks.json.

  • Verrouillez les versions sur des versions sûres. Pour les trois packages @cap-js, privilégiez comme version cible les versions publiées par SAP après l'incident (@cap-js/db-service@2.11.0, @cap-js/sqlite@2.4.0, @cap-js/postgres@2.3.0) et utilisez les versions antérieures à l'incident (2.10.0, 2.2.1 et 2.2.1, respectivement) comme versions minimales. Pour mbt, aucune version corrigée n'avait été publiée au moment de la rédaction ; verrouillez sur mbt@1.2.47 jusqu'à ce que SAP publie une version de remplacement.

Renforcement général de la sécurité :

  • Dans les environnements CI, utilisez par défaut npm install --ignore-scripts et n'autorisez explicitement les scripts de cycle de vie que pour les packages qui en ont réellement besoin. Cela neutralise toute la catégorie des vols d'identifiants via preinstall, qui a servi de mécanisme de diffusion pour le Shai-Hulud original, SHA1-Hulud et cette campagne. Le vecteur d'attaque par hook de cycle de vie a été signalé à npm en 2016 et considéré comme un comportement attendu, comme l'a de nouveau souligné paulirish sur Hacker News ; dix ans plus tard, il reste la surface la plus exploitée de l'écosystème. Snyk en dit plus dans ses bonnes pratiques de sécurité npm et propose une analyse plus approfondie des défenses en amont dans son article Comment prévenir les packages malveillants.

  • Envisagez des gestionnaires de packages qui désactivent par défaut les scripts de cycle de vie pour une sécurité renforcée. pnpm v10 bloque les scripts de cycle de vie sauf autorisation explicite, et Bun utilisé comme programme d'installation est livré avec une liste d'autorisation de packages approuvés activée par défaut. Ce dernier point est particulièrement pertinent ici : le logiciel malveillant utilise Bun comme environnement d'exécution pour lancer sa charge utile, mais Bun utilisé comme programme d'installation aurait bloqué le hook preinstall qui la déploie. La communauté Bun suit également une demande de configuration minimumReleaseAge (#28729) visant une mesure d'atténuation par délai de grâce, conformément à l'argumentaire de Yossarian en faveur des délais de grâce pour les dépendances.

  • Surveillez les modifications inattendues apportées à .claude/settings.json et .vscode/tasks.json dans les différences de PR. Considérez tout ajout à l'un ou l'autre de ces fichiers comme un signe potentiel d'attaque de la chaîne d'approvisionnement, même si ces ajouts ressemblent à des commits de routine visant à maintenir les dépendances à jour.

  • Pour les équipes SOC et d’ingénierie de la détection, les requêtes Microsoft Defender KQL publiées dans m4nbat/100_days_of_kql_2026 (jour 17) détectent la chaîne Bun + TruffleHog + /proc/mem réutilisée par cette campagne. Elles ont été conçues pour SHA1-Hulud et s’appliquent à Mini Shai-Hulud sans aucune modification. Le flux d’IOC de Wiz Research et gensecaihq/Shai-Hulud-2.0-Detector constituent des listes de blocage utiles, dès que leurs responsables les auront mises à jour avec les quatre nouveaux packages.

  • Adoptez une approche de priorisation fondée sur les risques pour concentrer la rotation et le triage sur les identifiants dont le périmètre d’impact est le plus large. Tous les secrets concernés ne présentent pas le même niveau de sensibilité, et le dépôt secret chiffré laisse les équipes de défense avec des informations incomplètes.

Sécurisez vos applications Python dès maintenant

Détectez et corrigez gratuitement les vulnérabilités Python avec Snyk.

Aucune carte de crédit requise.

Ou inscrivez-vous avec Azure AD Docker ID Bitbucket

En utilisant Snyk, vous acceptez de respecter nos politiques, notamment nos Conditions d’utilisation et notre Politique de confidentialité.