id: shai-hulud-supply-chain

info:
  name: Shai Hulud 2.0 - Supply Chain Malware Detection
  author: princechaddha,wiz-research
  severity: critical
  description: |
    Detects compromised npm packages from the Shai Hulud 2.0 supply chain attack discovered in November 2025.
    The attack affected over 25,000 malicious repositories across approximately 350 GitHub users, targeting major organizations
    including Zapier, ENS Domains, PostHog, Postman, AsyncAPI, Voiceflow, and BrowserBase. The malware executes during the
    preinstall phase and performs credential theft, cloud resource access (AWS, Azure, GCP), and GitHub persistence through
    self-hosted runners named 'SHA1HULUD'. Malicious versions were published between November 21-23, 2025.
  reference:
    - https://www.wiz.io/blog/shai-hulud-2-0-ongoing-supply-chain-attack
    - https://www.aikido.dev/blog/shai-hulud-strikes-again-hitting-zapier-ensdomains
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
    cvss-score: 9.6
    cwe-id: CWE-1357
  metadata:
    verified: true
    max-request: 1
  tags: file,malware,supply-chain,npm,nodejs,shai-hulud

file:
  - extensions:
      - json

    extractors:
      - type: regex
        name: zapier-compromised
        regex:
          - '"@zapier/secret-scrubber":\s*"[^"]*1\.1\.[345][^"]*"'
          - '"@zapier/ai-actions":\s*"[^"]*0\.1\.(18|19|20)[^"]*"'
          - '"@zapier/babel-preset-zapier":\s*"[^"]*6\.4\.[123][^"]*"'
          - '"@zapier/browserslist-config-zapier":\s*"[^"]*1\.0\.[345][^"]*"'
          - '"zapier-platform-cli":\s*"[^"]*18\.0\.[234][^"]*"'
          - '"zapier-platform-core":\s*"[^"]*18\.0\.[234][^"]*"'
          - '"zapier-platform-schema":\s*"[^"]*18\.0\.[234][^"]*"'
          - '"zapier-scripts":\s*"[^"]*7\.8\.[34][^"]*"'
          - '"zapier-async-storage":\s*"[^"]*1\.0\.[123][^"]*"'

      - type: regex
        name: ensdomains-compromised
        regex:
          - '"@ensdomains/address-encoder":\s*"[^"]*1\.1\.5[^"]*"'
          - '"@ensdomains/contracts":\s*"[^"]*1\.6\.1[^"]*"'
          - '"@ensdomains/ensjs":\s*"[^"]*4\.0\.3[^"]*"'
          - '"@ensdomains/content-hash":\s*"[^"]*3\.0\.1[^"]*"'
          - '"@ensdomains/ens-avatar":\s*"[^"]*1\.0\.4[^"]*"'
          - '"@ensdomains/blacklist":\s*"[^"]*1\.0\.1[^"]*"'
          - '"@ensdomains/buffer":\s*"[^"]*0\.1\.2[^"]*"'
          - '"@ensdomains/ccip-read-[^"]*":\s*"[^"]*0\.(0|1)\.\d+[^"]*"'
          - '"@ensdomains/cypress-metamask":\s*"[^"]*1\.2\.1[^"]*"'
          - '"@ensdomains/dnsprovejs":\s*"[^"]*0\.5\.3[^"]*"'
          - '"@ensdomains/ens-test-env":\s*"[^"]*1\.0\.2[^"]*"'
          - '"@ensdomains/ens-validation":\s*"[^"]*0\.1\.1[^"]*"'
          - '"@ensdomains/mock":\s*"[^"]*2\.1\.52[^"]*"'
          - '"@ensdomains/thorin":\s*"[^"]*0\.6\.51[^"]*"'
          - '"@ensdomains/ui":\s*"[^"]*3\.4\.6[^"]*"'
          - '"ethereum-ens":\s*"[^"]*0\.8\.1[^"]*"'
          - '"crypto-addr-codec":\s*"[^"]*0\.1\.9[^"]*"'

      - type: regex
        name: posthog-compromised
        regex:
          - '"@posthog/agent":\s*"[^"]*1\.24\.1[^"]*"'
          - '"@posthog/ai":\s*"[^"]*7\.1\.2[^"]*"'
          - '"@posthog/cli":\s*"[^"]*0\.5\.15[^"]*"'
          - '"@posthog/clickhouse":\s*"[^"]*1\.7\.1[^"]*"'
          - '"@posthog/core":\s*"[^"]*1\.5\.6[^"]*"'
          - '"@posthog/icons":\s*"[^"]*0\.36\.1[^"]*"'
          - '"@posthog/wizard":\s*"[^"]*1\.18\.1[^"]*"'
          - '"posthog-js":\s*"[^"]*1\.(167|168|169|297)\.\d+[^"]*"'
          - '"posthog-node":\s*"[^"]*[45]\.(11|13|18)\.\d+[^"]*"'
          - '"posthog-docusaurus":\s*"[^"]*2\.0\.6[^"]*"'
          - '"posthog-react-native":\s*"[^"]*4\.(11|12)\.\d+[^"]*"'
          - '"posthog-plugin-hello-world":\s*"[^"]*1\.0\.1[^"]*"'

      - type: regex
        name: postman-compromised
        regex:
          - '"@postman/csv-parse":\s*"[^"]*4\.0\.[345][^"]*"'
          - '"@postman/node-keytar":\s*"[^"]*7\.9\.[456][^"]*"'
          - '"@postman/tunnel-agent":\s*"[^"]*0\.6\.[567][^"]*"'
          - '"@postman/aether-icons":\s*"[^"]*2\.23\.[234][^"]*"'

      - type: regex
        name: asyncapi-compromised
        regex:
          - '"@asyncapi/studio":\s*"[^"]*1\.0\.[23][^"]*"'
          - '"@asyncapi/server-api":\s*"[^"]*0\.16\.(24|25)[^"]*"'
          - '"@asyncapi/dotnet-rabbitmq-template":\s*"[^"]*1\.0\.[12][^"]*"'
          - '"@asyncapi/go-watermill-template":\s*"[^"]*0\.2\.(76|77)[^"]*"'
          - '"@asyncapi/java-template":\s*"[^"]*0\.3\.[56][^"]*"'
          - '"@asyncapi/keeper":\s*"[^"]*0\.0\.[23][^"]*"'
          - '"@asyncapi/php-template":\s*"[^"]*0\.1\.[12][^"]*"'
          - '"@asyncapi/python-paho-template":\s*"[^"]*0\.2\.(14|15)[^"]*"'
          - '"@asyncapi/web-component":\s*"[^"]*2\.6\.[67][^"]*"'
          - '"@asyncapi/edavisualiser":\s*"[^"]*1\.2\.[12][^"]*"'
          - '"asyncapi-preview":\s*"[^"]*1\.0\.[12][^"]*"'
          - '"create-glee-app":\s*"[^"]*0\.2\.[23][^"]*"'

      - type: regex
        name: voiceflow-compromised
        regex:
          - '"@voiceflow/alexa-types":\s*"[^"]*2\.15\.(60|61)[^"]*"'
          - '"@voiceflow/anthropic":\s*"[^"]*0\.4\.[45][^"]*"'
          - '"@voiceflow/api-sdk":\s*"[^"]*3\.28\.(58|59)[^"]*"'
          - '"@voiceflow/backend-utils":\s*"[^"]*5\.0\.[12][^"]*"'
          - '"@voiceflow/base-types":\s*"[^"]*2\.136\.[23][^"]*"'
          - '"@voiceflow/body-parser":\s*"[^"]*1\.21\.[23][^"]*"'
          - '"@voiceflow/chat-types":\s*"[^"]*2\.14\.(58|59)[^"]*"'
          - '"@voiceflow/common":\s*"[^"]*8\.9\.[12][^"]*"'
          - '"@voiceflow/eslint-config":\s*"[^"]*7\.16\.[45][^"]*"'
          - '"@voiceflow/general-types":\s*"[^"]*3\.2\.(22|23)[^"]*"'
          - '"@voiceflow/google-types":\s*"[^"]*2\.21\.(12|13)[^"]*"'
          - '"@voiceflow/runtime":\s*"[^"]*1\.29\.[12][^"]*"'

      - type: regex
        name: browserbase-compromised
        regex:
          - '"@browserbasehq/stagehand":\s*"[^"]*3\.0\.4[^"]*"'
          - '"@browserbasehq/mcp-server-browserbase":\s*"[^"]*2\.4\.2[^"]*"'
          - '"@browserbasehq/director-ai":\s*"[^"]*1\.0\.3[^"]*"'
          - '"@browserbasehq/bb9":\s*"[^"]*1\.2\.21[^"]*"'
          - '"@browserbasehq/mcp":\s*"[^"]*2\.1\.1[^"]*"'

      - type: regex
        name: accordproject-compromised
        regex:
          - '"@accordproject/concerto-analysis":\s*"[^"]*3\.24\.1[^"]*"'
          - '"@accordproject/concerto-linter":\s*"[^"]*3\.24\.1[^"]*"'
          - '"@accordproject/concerto-types":\s*"[^"]*3\.24\.1[^"]*"'
          - '"@accordproject/template-engine":\s*"[^"]*2\.7\.2[^"]*"'

      - type: regex
        name: other-compromised-scoped
        regex:
          - '"@actbase/react-native-[^"]*":\s*"[^"]*[0-9]+\.[0-9]+\.[0-9]+[^"]*"'
          - '"@antstackio/[^"]*":\s*"[^"]*[0-9]+\.[0-9]+\.[0-9]+[^"]*"'
          - '"@clausehq/flows-step-[^"]*":\s*"[^"]*0\.1\.14[^"]*"'
          - '"@dev-blinq/[^"]*":\s*"[^"]*1\.0\.[0-9]+[^"]*"'
          - '"@kvytech/[^"]*":\s*"[^"]*0\.0\.[0-9]+[^"]*"'
          - '"@lessondesk/[^"]*":\s*"[^"]*[0-9]+\.[0-9]+\.[0-9]+[^"]*"'
          - '"@trigo/[^"]*":\s*"[^"]*[0-9]+\.[0-9]+\.[0-9]+[^"]*"'
          - '"@varsityvibe/[^"]*":\s*"[^"]*[0-9]+\.[0-9]+\.[0-9]+[^"]*"'

      - type: regex
        name: malicious-indicators
        regex:
          - 'SHA1HULUD'
          - 'SHAI-HULUD'
          - 'shai-hulud'
# digest: 4a0a00473045022044a941bb4a169ab032c61fda553bafea4f00744b398fd40ca246c31e0186b2cc022100ff6ac326626b807b20362c737941d4ef5931a724fdead3674149eaa8613009a4:922c64590222798bb761d5b6d8e72950