Ciberamenazas
Shai-hulud 2.0 Campaign Targets Cloud and Developer Ecosystems
Shai-hulud 2.0 campaign features a sophisticated variant capable of stealing credentials and secrets from major cloud platforms and developer services, while automating the backdooring of NPM packages maintained by victims. Its advanced tactics enable rapid, stealthy propagation across the software supply chain, putting countless downstream users at risk.
Key takeaways:
- Shai-hulud 2.0 continues the first variant’s credential theft by stealing credentials and secrets from major cloud platforms as well as NPM tokens and GitHub authentication credentials, but introduces backdoor capabilities.
- The malware automates supply chain compromise by backdooring all NPM packages maintained by the victim, republishing them with malicious payloads that execute on installation, creating a highly wormable threat with the potential to impact thousands of downstream users.
- The malware uses stolen cloud credentials to access cloud-native secret management services, while also exhibiting destructive code that wipes user data when unsuccessful in harvesting data.
- Trend Vision One™ detects and blocks the indicators of compromise (IOCs) outlined in this blog, and provides customers with tailored threat hunting queries, threat insights, and intelligence reports.
This blog continues our investigation on the Node Package Manager (NPM) supply chain attack that took place on September 15, where attackers executed a highly targeted phishing campaign to compromise the account of an NPM package maintainer. Our previous blog detailed how the malicious code injected onto JavaScript packages diverted cryptocurrency assets by hijacking web APIs and manipulating network traffic, and how the Shai-hulud worm in the attack payload steals cloud service tokens, deploys secret-scanning tools, and spreads to additional accounts. An incident this November 24 reported hundreds of NPM repositories compromised by what appears to be a new Shai-hulud campaign with the repository description, "Sha1-Hulud: The Second Coming."
This blog discusses Trend™ Research findings on Shai-hulud 2.0 and reveals new functions that weren’t observed in its first variant.
Our analysis of Shai-hulud 2.0 reveals that it can steal credentials from AWS, GCP, and Azure cloud providers, which can contain API keys, tokens, and passwords, along with NPM tokens and GitHub authentication credentials. The malware also creates GitHub Actions workflows that allow for command-and-control (C&C). It also injects GitHub Actions workflow mechanisms that are specifically designed to steal repository secrets.
Beyond stealing static credentials, the malware uses stolen cloud credentials to access cloud-native secret management services: it can retrieve secrets from AWS using the AWS Secrets Manager API, extracts Google Cloud secrets through the GCP Secret Manager API, and collects Azure secrets via Azure Key Vault. The malware also targets credentials from Azure Pod Identity, a legacy system that remains widely used for providing Azure identities to Kubernetes pods.
To top all the capabilities, the malware also automatically backdoors every NPM package maintained by the victim, republishing them with malicious payloads that run during package installation, creating a wormable vector capable of spreading exponentially across the NPM ecosystem and potentially compromising thousands of downstream users who trust the affected packages. This entire workflow is automated and parallelized across up to 100 packages at once, maximizing propagation while keeping detection opportunities minimal.
Shai-hulud 2.0 attack chain analysis
Shai-Hulud 2.0 is delivered as an NPM package with a malicious preinstall script that executes automatically during the NPM installation process (modified package.json with "preinstall": "node setup_bun.js").
setup_bun.js (Loader)
The initial dropper setup_bun.js script serves as a loader that executes during the NPM package installation process. Its primary purpose is to ensure that a Bun JavaScript runtime is available on the victim's system and then uses it to execute the main malware payload (bun_environment.js).
Bun runtime detection and installation
The initial phase of the setup script involves detecting whether a Bun JavaScript runtime is already installed on the victim's system. This detection process uses platform-specific commands to search the system PATH for the Bun executable. On Windows systems, the script executes the where command, while Unix-like systems (Linux and macOS) use the which command.
If Bun is not detected in the system PATH, the script initiates an automatic download and installation process. This process uses official Bun installation scripts provided by bun.sh, which adds legitimacy to the installation and reduces the likelihood of detection by security software.
On Windows, the script uses PowerShell to download and execute the installation script via the Invoke-RestMethod and Invoke-Expression cmdlets. On Unix-like systems, it uses curl to download the installation script and pipes it directly to bash for execution. This approach mirrors the official Bun installation instructions, making the malware's behavior appear legitimate.
Reloading PATH environment
After installing the Bun runtime, the setup script must reload the system PATH environment variable to detect the newly installed executable. This is necessary because the Bun installation process modifies the user's PATH, but these changes are not immediately visible to the already-running Node.js process executing the setup script. The PATH reloading mechanism uses platform-specific techniques to retrieve the updated environment configuration.
On Windows systems, the script queries the Windows Registry using PowerShell to retrieve both user-level and machine-level PATH variables, then combines them into a single PATH string. This approach ensures that the Bun installation is detected regardless of whether it was installed to the user's profile directory or a system-wide location. The script uses the [Environment]::GetEnvironmentVariable() .NET method accessed through PowerShell to read these registry values.
On Unix-like systems, the PATH reloading process is more complex due to the variety of shell configurations that might be in use. The script attempts to source common shell profile files including .bashrc, .bash_profile, .profile, and .zshrc in the user's home directory.
Payload execution
The final phase of the setup script orchestrates the execution of the actual malware payload.
The script first checks if Bun is available in the system PATH which would be the case if Bun was previously installed or just successfully installed in an earlier step. If not found in PATH, the script searches for a locally bundled Bun executable that might have been included with the malicious package. The local Bun search examines several possible file paths within a bun-dist directory that could be bundled with the package. This includes checking for both Unix-style executable names (bun) and Windows executable names (bun.exe) in various subdirectory structures.
Once a Bun executable is located or installed, the script proceeds to execute the main malware payload stored in bun_environment.js. The script spawns the Bun process with the payload file as an argument.
bun_environment.js (main payload)
jy1() function
The jy1() function is the main entry point of the Shai-hulud 2.0 malware payload. When bun.exe bun_environment.js executes, this function is invoked at the script's top level and orchestrates the entire attack sequence.
CI/CD environment checking
The malware checks for CI/CD environment variables to determine if it's running in a continuous integration pipeline or on a developer's local machine. When detected, the malware executes immediately without background spawning to maximize credential access during build pipelines.
- BUILDKITE - Buildkite CI/CD platform
- PROJECT_ID - Google Cloud Build
- GITHUB_ACTIONS - GitHub Actions workflows
- CODEBUILD_BUILD_NUMBER - AWS CodeBuild
- CIRCLE_SHA1 - CircleCI pipelines
If none of these variables exist in process.env, it concludes the environment is a regular developer machine rather than a CI/CD pipeline, which triggers the stealth execution path with background process spawning.
Developer machine execution
The malware uses a stealth approach on developer machines by spawning a detached background process using Bun.spawn().unref() with the POSTINSTALL_BG=1 environment variable flag, which allows the parent process to exit immediately so NPM install completes in normal timing (2-3 seconds, avoiding user suspicion). This happens while the background child process, which inherited all environment variables including credentials, continues running completely hidden from the user to steal credentials.
aL0() function
aL0() is an asynchronous JavaScript function that targets CI/CD environments and developer workstations to steal credentials from AWS, GCP, and Azure cloud providers, along with NPM tokens and GitHub authentication credentials. When authentication fails, the malware executes destructive commands to wipe user data.The function begins by detecting if it's running in a GitHub Actions CI environment.
The malware uses 3 functions to establish persistence and disable security controls on Linux systems. The cQ0() function performs process detection by checking if the malware agent is already running on the system by searching for "/home/agent/agent" in the process list.
The pQ0() function attempts privilege escalation by first testing whether passwordless sudo access is available, and if not, it exploits Docker's privileged container access to mount the host filesystem and modify the sudoers configuration file to grant itself unrestricted root privileges.
Finally, the gQ0() function disables security controls by stopping and reconfiguring the systemd-resolved DNS service with a malicious configuration file, then systematically flushing iptables firewall rules in both the OUTPUT and DOCKER-USER chains to remove any network filtering that could block command-and-control (C&C) communications or data exfiltration.
Next, the malware instantiates modules for three major cloud providers and GitHub to prepare credential harvesting modules for AWS, Google Cloud Platform, Azure, and GitHub.
NPM token retrieval
The malware uses a credential theft module that targets NPM authentication tokens from developer workstations. It searches for .NPMrc configuration files in two locations: the current working directory and the user's home directory, which are standard locations where NPM stores registry authentication credentials. The function reads these files line by line, skipping comments and empty lines, then uses a regular expression pattern to extract NPM authentication tokens that match the format _authToken= or :_authToken= followed by a base64-encoded token string.
The malware then validates the token by calling NPM's /-/whoami API endpoint to verify the token works and retrieve the authenticated username. The whoami function verifies NPM authentication and retrieves the victim's NPM username, which is then used to query for packages they maintain. If validation succeeds, the username is stored and used in a later stage to enumerate all packages the victim maintains (up to 100 packages) and the validated token is then used to publish backdoored versions of those packages to the NPM registry.
Command-and-control
The malware creates a GitHub repository and establishes C&C infrastructure. It first verifies that GitHub authentication is available to ensure the malware has valid stolen GitHub credentials before proceeding. It then generates an 18-character random identifier that will serve as the unique repository name for this specific infected victim, ensuring each compromised machine has its own dedicated C&C repository.
- Repository creation via GitHub API
The createRepo() function uses the GitHub Octokit API to call repos.createForAuthenticatedUser() with the random name, the description "Shai-Hulud: The Second Coming.", and specific configuration settings including public visibility, discussions enabled, and all other features like issues, projects, and wiki disabled to keep the repository minimal and focused on C&C operations.
After successful creation, it extracts the repository owner's login username and the repository name from the API response, then constructs the full repository path in the format "owner/repo" and stores it in this.gitRepo for future reference.
- Workflow permission verification
It calls checkWorkflowScope() to validate whether the stolen GitHub token has the workflow OAuth scope permission, which is required to manage GitHub Actions workflows and runners. It sends a HEAD request to GitHub's API and examines the x-oauth-scopes response header, which contains a comma-separated list of token permissions. The function parses this header, checks if "workflow" is present in the list, and caches the result in this.hasWorkflow. If the workflow scope exists, the malware can proceed with deploying self-hosted runners and C&C workflows.
The malware then requests a runner registration token from GitHub's API using a POST request to /repos/{owner}/{repo}/actions/runners/registration-token, which returns a temporary token needed to register a self-hosted runner with the repository.
- Platform-specific runner deployment
Based on the detected operating system (Linux, Windows, or macOS), the malware downloads the appropriate GitHub Actions runner binary from the official GitHub releases, extracts it to a hidden directory ($HOME/.dev-env on Unix or the user's home directory on Windows), and configures it with the registration token to connect back to the newly created repository with the runner name "SHA1HULUD". The runner is launched in the background using nohup on Unix systems or a hidden PowerShell window on Windows, ensuring it continues running even after the initial malware process exits and establishing persistent access to the compromised machine.
- C&C workflow installation
The malware creates a GitHub Actions workflow file at .github/workflows/discussion.yaml in the repository that triggers whenever a discussion is created, allowing the attacker to execute arbitrary commands on the infected machine by simply posting messages in the repository's discussion section, completing the C&C infrastructure setup.
- Anti-analysis failsafe
If an NPM token is invalid or not found, and the malware also fails to obtain a valid GitHub token, it executes destructive commands that attempt to delete all files in the user's home directory.
- System information collection
The malware then collects detailed system information and GitHub credentials to build a comprehensive profile of the victim system including platform details, hostname, OS user information, and GitHub authentication status.
Malicious workflow creation for secret exfiltration
In addition to the discussion.yaml workflow shown above, the malware creates another GitHub Actions workflow specifically designed to steal all repository secrets. The workflow injection mechanism leverages GitHub's native CI/CD infrastructure to automatically exfiltrate sensitive data whenever code is pushed to compromised repositories.
Workflow injection mechanism
The malware systematically iterates through all repositories accessible to the compromised GitHub account, creating malicious workflow files in each one. To avoid immediate detection, the malware first creates a temporary branch with a timestamped name following the pattern add-linter-workflow-{timestamp}. This branch naming convention appears legitimate, mimicking common development practices where developers create feature branches for adding code quality tools like linters and formatters. By injecting the malicious workflow on a separate branch rather than directly on the main branch, the malware reduces the risk of triggering branch protection rules or immediate code review processes that might expose the malicious activity.
Malicious workflow content
The malicious workflow file is carefully crafted to appear as a legitimate code formatting tool while concealing its true purpose of credential exfiltration. The workflow is named "Code Formatter" and configured to trigger on every push event, ensuring it executes automatically whenever any developer commits code to the repository. The core of the attack leverages GitHub Actions' built-in secrets context, which provides access to all repository secrets configured in the repository settings. By using the toJSON() function, the malware serializes the entire secrets object into a JSON string, capturing every credential stored in the repository including cloud provider keys, API tokens, database passwords, and signing certificates.
Workflow execution monitoring
After injecting the malicious workflow file into the target repository, the malware enters a monitoring phase where it actively polls the GitHub Actions API to detect when the workflow executes and completes. The malware implements a polling loop with a 30-second timeout, repeatedly querying the repository's workflow runs every 2 seconds to identify the newly created workflow execution. This monitoring mechanism is necessary because the workflow only triggers when code is pushed to the repository, and the malware needs to wait for either an existing automated process or a developer to push code that will trigger the malicious workflow.
Artifact download and secret extraction
Once the workflow begins execution, the malware tracks its progress by checking the workflow status, waiting for it to transition to "completed" before attempting to download the exfiltrated secrets from the workflow artifacts.
Once the workflow is completed, the malware queries the GitHub Actions Artifacts API to list all artifacts produced by the workflow run. GitHub Actions allows workflows to upload multiple artifacts, so the malware must enumerate the artifact list to identify the specific artifact containing the stolen secrets. The API returns an array of artifact objects, each containing metadata such as the artifact ID, name, size, and download URL. The malware iterates through this array looking for the artifact named "formatting" that was uploaded by the malicious workflow's actions/upload-artifact@v5 step.
GitHub implements a two-step download process for artifacts to provide secure, time-limited access to artifact storage. The malware first requests the artifact download endpoint with the artifact ID, setting the redirect parameter to "manual" to prevent automatic redirect following. This initial request returns a Location header containing a temporary, pre-signed URL that points to the actual artifact storage location. The malware extracts this redirect URL from the response headers, then makes a second HTTP request to this temporary URL to download the actual ZIP file containing the stolen secrets.
After successfully downloading the artifact ZIP file, the malware must extract the format.json file containing the stolen repository secrets. The download response is received as an ArrayBuffer, which the malware converts to a Node.js Buffer object for processing. Using a ZIP archive library (referenced as tG0["default"]), the malware opens the ZIP archive and calls getEntry("format.json") to locate the specific file containing the exfiltrated secrets. Once the entry is found, the malware extracts the file data and converts it from binary to a UTF-8 string, revealing the JSON-formatted repository secrets that were captured by the malicious workflow.
Multi-cloud credential harvesting
The malware simultaneously harvests credentials from all three major cloud providers by first capturing the complete set of environment variables, which may contain API keys, tokens, and passwords. It then retrieves secrets from AWS using the AWS Secrets Manager API, extracts Google Cloud secrets through the GCP Secret Manager API, and collects Azure secrets via Azure Key Vault.
AWS credential collection
The malware implements AWS credential harvesting by leveraging the AWS SDK's built-in credential provider chain. This mechanism automatically searches for credentials in environment variables following the standard AWS credential lookup order. The implementation uses a getter method that checks for the presence of required AWS environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) and extracts them along with optional session tokens.
The credential extraction function operates asynchronously and includes detailed logging capabilities that can be enabled through the malware's configuration. When credentials are found, the function constructs a credential object containing the access key ID, secret access key, and session token (if present). Additionally, the malware captures extended credential metadata including expiration timestamps, credential scope information, and AWS account IDs.
The malware also targets AWS configuration files stored in the user's home directory by implementing file path resolution functions that follow AWS CLI conventions. The implementation first checks for custom file paths specified through environment variables (AWS_CONFIG_FILE and AWS_SHARED_CREDENTIALS_FILE), then falls back to default locations in the ~/.aws/ directory.
The malware includes specialized functionality for stealing credentials from containerized environments, specifically targeting AWS ECS (Elastic Container Service) and EKS (Elastic Kubernetes Service) task credential mechanisms. The implementation checks for container-specific environment variables that point to credential endpoints exposed by the container runtime. These endpoints provide temporary credentials with IAM role permissions assigned to the container task, making them highly valuable for attackers seeking to move laterally within cloud infrastructure.
Google Cloud Platform (GCP) credential collection
The malware also targets Google Cloud Platform's Application Default Credentials (ADC) system, which is the recommended authentication method for GCP applications. The implementation begins by checking the GOOGLE_APPLICATION_CREDENTIALS environment variable (case-insensitive to catch variations), which typically points to a service account JSON key file. When the environment variable is found, the malware attempts to read the referenced credential file and extract the service account private key, client email, and project information.
The malware implements platform-aware logic to locate the Google Cloud SDK configuration directory, which stores authenticated user credentials and project settings. The function first checks for the CLOUDSDK_CONFIG environment variable that allows users to customize the configuration directory location. If this variable is not set, the malware determines the appropriate default path based on the operating system, using %APPDATA%\gcloud on Windows systems and ~/.config/gcloud on Unix-like systems.
Once the configuration directory is located, the malware accesses multiple credential stores within this directory and various authentication tokens cached by the gcloud CLI.
The malware implements a targeted file existence check and extraction routine specifically for the Application Default Credentials JSON file. The implementation includes defensive programming with an existence check (existsSync) to avoid errors when the file is not present, silently failing and setting the path to null rather than throwing exceptions that might alert monitoring systems.
Azure credential collection
The malware also implements a comprehensive Azure credential harvesting system that targets the entire spectrum of Azure authentication methods. The implementation begins by defining an array of critical Azure environment variables and systematically checking for their presence in the process environment. The credential provider includes intelligent parsing logic that handles complex configurations such as semicolon-delimited tenant lists and boolean flag conversions.
The malware logs discovered environment variables using a verbose logging system, providing attackers with visibility into which authentication methods are available on the compromised system.
The malware implements a cascading credential extraction system that attempts multiple Azure authentication methods. The implementation first attempts to extract Service Principal credentials with client secrets (the most common authentication method for automated systems), which requires a tenant ID, client ID, and client secret. If these three values are present, the malware instantiates a ClientSecrietCredential object that can be used to authenticate to Azure Resource Manager and access Azure resources with the permissions granted to the service principal. Each successful credential extraction is logged with tenant and client IDs.
If client secret authentication fails, the malware falls back to certificate-based authentication by checking for AZURE_CLIENT_CERTIFICATE_PATH, and optionally, AZURE_CLIENT_CERTIFICATE_PASSWORD.
The malware then attempts username and/or password authentication though it includes warning logic suggesting this method is deprecated.
The malware also includes support for extracting Workload Identity credentials, a modern Azure authentication mechanism used primarily in Kubernetes environments. The implementation targets three critical environment variables: AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_FEDERATED_TOKEN_FILE.
The malware also targets credentials from Azure Pod Identity, a legacy system that remains widely used for providing Azure identities to Kubernetes pods.
The implementation checks for the AZURE_POD_IDENTITY_AUTHORITY_HOST environment variable, which points to the Instance Metadata Service (IMDS) endpoint that provides managed identity tokens. When this variable is present, the malware constructs the full OAuth token endpoint URL by appending the standard token path to the authority host.
If the environment variable is not set, the malware falls back to the standard Azure IMDS endpoint.
Active Cloud secret manager exploitation
Beyond stealing static credentials, the malware uses stolen cloud credentials to access cloud-native secret management services.
The implementation includes dedicated processes for AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault, each implementing the listAndRetrieveAllSecrets() method to enumerate and extract secrets stored in these services.
AWS secrets manager
The AWS secret harvesting module implements a multi-region secret harvesting strategy that maximizes the number of secrets retrieved. The WX class first validates stolen AWS credentials using the STS GetCallerIdentity API call to ensure they are active and to extract identity information (User ID, Account ID, ARN).
Once credentials are validated, the malware iterates through 17 major AWS regions to discover secrets stored in regional Secrets Manager services. For each region, the malware calls the ListSecrets API to enumerate available secrets, then retrieves each secret's value using GetSecretValue.
GCP secrets manager
The GCP secret-harvesting module uses advanced authentication handling, first validating access by calling getAccessToken() from the Google Auth library. Once credentials are confirmed, the malware queries the Resource Manager API to list all accessible GCP projects, then creates a Secret Manager client for each project. It enumerates secrets with listSecrets() and retrieves their latest versions using the {secretName}/versions/latest path, extracting both the secret payload and associated metadata.
Azure Key Vault
The Azure secret harvesting implementation targets Microsoft's Key Vault service by first authenticating using the DefaultAzureCredential provider, which attempts multiple authentication methods in sequence (environment variables, managed identity, Azure CLI credentials). Once authenticated, the malware uses the Resource Manager API to list all Key Vault resources in the subscription by filtering for resources with type Microsoft.KeyVault/vaults. For each discovered vault, the malware instantiates a SecretClient and iterates through all secrets, retrieving their values.
TruffleHog secret scanning
The malware uses an automated TruffleHog deployment system that downloads, extracts, and caches the latest version of the tool directly from GitHub. It Before downloading anything, it checks its cache for an existing TruffleHog binary; if none is found, it fetches the latest release info from GitHub, downloads the correct binary for the system, extracts it, and makes it executable.
The malware uses the GitHub API to automatically retrieve the latest TruffleHog release information without needing authentication, sending a GET request to /repos/trufflesecurity/trufflehog/releases/latest to obtain metadata and platform-specific download links. This removes the need to hard-code version numbers and ensures it remains compatible with future updates.
The malware uses TruffleHog’s filesystem scanner to sweep the victim’s home directory for hardcoded secrets, invoking the tool with JSON output for easy parsing and optional arguments to narrow or customize the scan. It runs the scan with a 10-minute timeout to avoid long, suspicious execution times, capturing both output and errors. The results are packaged into a structured report containing discovered secrets, errors, scan duration, and the tool’s exit code, allowing operators to quickly assess whether the scan succeeded, partially completed, or failed.
Data exfiltration
The malware implements a multi-stage exfiltration system that aggregates and uploads four distinct categories of stolen data to an attacker-controlled Git repository that the malware automatically creates under the victim's own GitHub account. The exfiltration process creates four separate JSON files, each containing specific categories of stolen data.
| File Name | Description |
| contents.json | Aggregates system metadata such as platform details, hostname, OS user information, and GitHub authentication status. |
| environment.json | Dumps all environment variables, capturing cloud credentials, API keys, database strings, and other sensitive config data. |
| cloud.json | Contains secrets retrieved from AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault, showing that the malware uses stolen credentials to access cloud-native secret stores. |
| truffleSecrets.json | Stores TruffleHog scan results, including hardcoded secrets found in source code, config files, and other documents within the user's home directory. |
Supply chain propagation
The malware automatically backdoors every NPM package maintained by the victim, republishing them with malicious payloads that run during package installation. This creates a wormable vector capable of spreading exponentially across the NPM ecosystem and potentially compromising thousands of downstream users who trust the affected packages.
The attack unfolds in five phases: discovering all packages owned by the victim, downloading their original tarballs, injecting malicious preinstall hooks, bundling the malware installer, and republishing the modified packages as legitimate updates.
This entire workflow is automated and parallelized across up to 100 packages at once, maximizing propagation while keeping detection opportunities minimal.
Maintainer package retrieval
The malware queries the NPM registry to discover all packages maintained by the authenticated victim. The implementation uses NPM's search API with the maintainer: filter to enumerate packages owned by the compromised account. The package enumeration includes detailed metadata collection for each discovered package, including download statistics that allow the malware to prioritize high-impact targets. By sorting packages by monthly downloads in descending order, the attack maximizes potential victim count by compromising the most popular packages first.
NPM registry search
The search implementation uses NPM's official search API endpoint (/-/v1/search) with proper URL encoding and authentication headers. The default search limit of 20 packages can be overridden, and in the actual attack execution, the malware requests up to 100 packages.
Package download and extraction
The malware downloads the original package tarball from the NPM registry, preparing it for modification. This ensures the backdoored version maintains all original functionality while adding malicious capabilities. The download process uses standard HTTP fetching with compression support (gzip, deflate, brotli) to efficiently retrieve packages. The temporary directory naming (NPM-update-) mimics legitimate NPM tooling to avoid detection by process monitoring systems.
Preinstall hook injection
The core of the supply chain attack involves modifying the package's package.json file to inject a malicious preinstall script. This script executes automatically when anyone runs NPM install on the package, even before the package's actual dependencies are installed.
The preinstall script executes during the NPM installation lifecycle at the earliest possible stage, specifically:
- Before dependency resolution
- Before package installation
- Before any legitimate package code runs
- With the user's full permissions
Malicious payload bundling
The malware bundles a sophisticated multi-stage installer script (setup_bun.js) that handles Bun runtime installation and malware execution as mentioned at the beginning of this analysis. This script is designed to work across Windows, Linux, and macOS platforms.
Package republishing
After injecting malicious code and bundling payloads, the malware repackages the modified package and publishes it to NPM using the victim's credentials. The publishing process uses the victim's NPM authentication token obtained earlier in the attack, making the malicious update appear as a legitimate release from the trusted package maintainer. The version bump (patch increment) follows semantic versioning conventions, making it appear as a bug fix or minor update that users would typically install without scrutiny.
Proactive security with Trend Vision One™
Trend Vision One™ is the only AI-powered enterprise cybersecurity platform that centralizes cyber risk exposure management and security operations, delivering robust layered protection across on-premises, hybrid, and multi-cloud environments.
The following sections contain Trend Vision One insights, reports, and queries mentioned in the previous blog with additional information from this report.
Trend Vision One™ Threat Intelligence
To stay ahead of evolving threats, Trend customers can access Trend Vision One™ Threat Insights which provides the latest insights from Trend™ Research on emerging threats and threat actors.
Trend Vision One Threat Insights
Trend Vision One Intelligence Reports (IOC Sweeping)
Hunting Queries
Trend Vision One Search App
Trend Vision One customers can use the Search App to match or hunt the malicious indicators mentioned in this blog post with data in their environment.
malName:*SHULUD* AND eventName: MALWARE_DETECTION AND LogType: detection
Indicators of Compromise (IoCs)
Indicators of Compromise can be found here.