Sitemap

Threat Intelligence | Red Hat Cloud Services npm Package Supply Chain Poisoning

20 min readJun 4, 2026

--

Press enter or click to view image in full size

Background

Recently, the MistEye security monitoring system detected intelligence indicating anomalous versions of multiple npm packages under the Red Hat Cloud Services organization. This incident involves a total of 32 npm packages and 96 versions under the organization. This article selects three local samples for in-depth offline analysis. These samples are neither impersonated namespaces nor typo-squatting packages; rather, they are legitimate package versions published under the @redhat-cloud-services scope. Analysis of the sample source code confirms that their tarballs were implanted with a multi-layer obfuscated malicious loader that is automatically triggered during the installation phase.

After complete reconstruction, it was confirmed that the core payloads of these three samples possess source-level capabilities including GitHub Actions Runner memory reading, multi-cloud and local credential harvesting, GitHub API exfiltration and dead-drop communication, GitHub workflow injection, npm self-propagation, persistence via Claude Code / VS Code / systemd / LaunchAgent, Harden-Runner / StepSecurity evasion, and EDR/security product detection. Based on the breadth of these capabilities, potential targets include developer workstations, CI/CD runners, build containers, GitHub repositories, GitHub Actions workflows, npm publishing pipelines, and cloud environment credentials. The actual impact scope requires further verification through installation logs, repository audits, and platform-side telemetry.

Based on its code structure, propagation paths, and combination of capabilities, this malware is a variant of the Shai-Hulud malware family.

MistEye Response

MistEye is a Web3 threat intelligence and dynamic security monitoring system independently developed by SlowMist. It integrates security monitoring and threat intelligence aggregation capabilities to provide users with real-time risk alerts and asset protection.

After detecting this Red Hat Cloud Services npm package supply chain poisoning incident and its associated malicious samples, the MistEye system triggered a high-severity alert. A systematic analysis was conducted on the attack chain’s obfuscation structure, payload decryption, capability reconstruction, and IOCs.

Press enter or click to view image in full size
https://enterprise.misteye.io/threat-intelligence/SM-2026-378450

Attack Chain Overview

The technical analysis presented in this article is based solely on local offline static analysis, including unpacking, decoding, and deobfuscation validation of three npm tgz samples.

The samples covered in this validation are as follows:

@redhat-cloud-services/frontend-components-config

  • Version: 6.11.3
  • tgz SHA-256:0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060

@redhat-cloud-services/types

  • Version: 3.6.1
  • tgz SHA-256:d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558

@redhat-cloud-services/rule-components

  • Version: 4.7.2
  • tgz SHA-256:aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f

The attack entry point is identical across all three samples: each package contains scripts.preinstall = “node index.js” in its package.json. This means that as soon as these versions are installed on a developer workstation or within a CI/CD environment, the root-level index.js is automatically executed during the installation phase, without requiring the user to explicitly import or run any application code.

The three samples share the same core malicious payload but differ in their outer-layer packaging parameters. Specifically, they use different ROT/Caesar shift values and AES-GCM keys / IVs / tags. As a result, static signatures based on outer-layer package hashes, fixed keys, or fixed shift values cannot be easily reused across packages. However, the decrypted Bun runtime bootstrapper and the core malicious payload have identical hashes across all samples: one component serves as a startup helper module for preparing the Bun runtime environment, while the other is the actual payload containing the malicious functionality. In this article, these components are referred to as the “Bun Runtime Bootstrapper” (source code variable name _b) and the “Core Malicious Payload” (source code variable name _p), respectively.

The reconstructed attack chain is as follows:

Press enter or click to view image in full size

Technical Analysis

1. Entry Point: npm Lifecycle Script Hijacking

All three samples trigger the attack chain through the preinstall lifecycle hook in package.json:

"scripts": {
"preinstall": "node index.js"
}

preinstall is automatically executed during the npm installation process. For ordinary frontend component, type definition, or rule component packages, there is typically no need to execute a large JavaScript file located in the package root during installation. This is the most direct indicator of anomalous behavior.

Sample-level evidence is as follows:

@redhat-cloud-services/frontend-components-config@6.11.3

  • main: lib/index.js
  • files field: [“/lib”, “/bin”]
  • Root-level index.js SHA-256: 545a1838c66e1771f58d84a17b3e1841e5eeab91a73f4ccc59c9492450a6d9c0

@redhat-cloud-services/types@3.6.1

  • main: index.d.ts
  • files field: not set
  • Root-level index.js SHA-256: b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966

@redhat-cloud-services/rule-components@4.7.2

  • main: index.js
  • files field: not set
  • Root-level index.js SHA-256: 1a30a9abe20bab121aaa75ed040565af14e6cdfb745609ee0e7b94a2d814fb9c

Among them, frontend-components-config@6.11.3 declares only “/lib” and “/bin” in its files field, yet an additional index.js exists in the tarball root directory and is invoked by preinstall. This anomaly applies only to this specific sample. Since types@3.6.1 and rule-components@4.7.2 do not define a files field, this anomaly should not be generalized across all samples.

Press enter or click to view image in full size

2. First Layer: Numeric Array + ROT/Caesar Letter Substitution

The root-level index.js files in all three samples are extremely large single-line JavaScript files with an identical structure. The main body consists of a try { eval(…) } catch (…) wrapper.

Press enter or click to view image in full size

This wrapper first reconstructs a string from a large numeric array using String.fromCharCode, then performs a ROT/Caesar shift on the alphabetic characters within the string, and finally passes the decoded result to eval for execution. The exception handler only outputs a wrapper: prefix, reducing the visibility of obvious errors in the event of installation failures.

The outer-layer shift values and Stage 2 hashes for the three samples are as follows:

frontend-components-config@6.11.3

  • index.js size: 4,294,798 bytes
  • ROT/Caesar shift:10
  • Stage 2 SHA-256:b19c2fd48535c8c40aeb3e627ce92775f33ef9292611767bb1236c238e6f90cc

types@3.6.1

  • index.js size: 4,135,588 bytes
  • ROT/Caesar shift:4
  • Stage 2 SHA-256:9c0425aa6e6d7792ac38d24f3e7245f42fcaa553ddfeb6bd97677017f10c3b75

rule-components@4.7.2

  • index.js size: 4,294,336 bytes
  • ROT/Caesar shift:11
  • Stage 2 SHA-256:d590bd375d95e4ac072b7ebc1fc4489bcaf5f20a939e92486267aa398bcf1e5d

3. Second Layer: AES-128-GCM Decryption of the Bun Bootstrapper and Core Payload

The Stage 2 code decoded from the ROT/Caesar layer uses Node.js crypto.createDecipheriv to perform AES-128-GCM (Advanced Encryption Standard — Galois/Counter Mode) decryption and sets the authentication tag through setAuthTag. The decryption targets are two subsequent components: the Bun Runtime Bootstrapper and the Core Malicious Payload.

Press enter or click to view image in full size

The Bun Runtime Bootstrapper is responsible for detecting, locating, or preparing a Bun runtime environment so that subsequent code can be executed through Bun. The Core Malicious Payload serves as the main body of the attack chain, containing the primary malicious capabilities including credential harvesting, GitHub/npm propagation, persistence, defensive evasion, and embedded resource decryption.

Each of the three samples uses different AES-128-GCM keys, initialization vectors, and authentication tags to encrypt these two components. However, after decryption, the SHA-256 hash of the Bun Runtime Bootstrapper is identical across all three samples:

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

Likewise, the SHA-256 hash of the Core Malicious Payload is identical across all three samples:

0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35

This indicates that the attacker changed the outer-layer packaging parameters across different npm packages while reusing the same set of core malicious components.

After decryption, Stage 2 writes the Core Malicious Payload to /tmp, executes it through Bun, and then deletes the temporary file. The actual logic reconstructed from all three samples is as follows:

Press enter or click to view image in full size

Therefore, the verifiable temporary file pattern across all three samples is:

/tmp/p<random>.js

The Bun Runtime Bootstrapper is 898 bytes in size, and its hash is identical across all three samples:

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

The Bun Runtime Bootstrapper contains logic involving child_process.execSync, fs.existsSync, fs.mkdtempSync, fs.chmodSync, os.platform(), os.arch(), and getBunPath(), which are used to locate or prepare a Bun runtime environment. In other words, Stage 2 does not simply assume that Bun is already installed globally on the system. When executed in a non-Bun runtime path, it first loads the Bun Runtime Bootstrapper and then invokes Bun through getBunPath() to execute the Core Malicious Payload.

Press enter or click to view image in full size

4. Third Layer: obfuscator.io String Table

The decrypted Core Malicious Payload is not directly readable plaintext JavaScript. Instead, it is further protected by an obfuscator.io-style string table obfuscation layer. This layer centralizes a large number of strings into an array and restores them through runtime indexing and rotation logic. As a result, analysts cannot directly search for critical APIs, paths, and configuration names until the string table reconstruction process has been completed.

5. Fourth Layer: B5 Custom String Encryption

After reconstructing the obfuscator.io string table, an additional B5 custom string encryption layer remains within the Core Malicious Payload. The confirmed parameters are as follows:

  • KDF:PBKDF2(Password-Based Key Derivation Function 2)
  • Hash Function: SHA-256
  • Iteration Count: 200000
  • Key Length: 32 bytes
  • Decryption Rounds: 3
  • password:ba2c6ddb3672bdd6a611e6850b4f700b52aed3dab2f1b3d5f8c839d4a157a709
  • salt:5b26508dc0f1075a7c0b4d8aa464487e

The decrypted results are as follows:

Press enter or click to view image in full size

Among the decrypted B5 content, multiple categories of critical plaintext strings become visible. It should be noted that some of these strings originally resided within the obfuscator.io string table and only become directly searchable via grep after both stages — string table reconstruction and B5 decryption — have been completed:

https://api.github.com
https://api.github.com/graphql
api.anthropic.com
v1/api
python-requests/2.31.0
tmp.0987654321.lock
OIDC_PACKAGES
WORKFLOW_ID
REPO_ID_SUFFIX
IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner
Miasma: The Spreading Blight

6. Additional Embedded Layer: AES-256-GCM + gzip

The Core Malicious Payload also contains embedded resources encrypted with AES-256-GCM and compressed with gzip. The reconstruction logic uses:

Press enter or click to view image in full size

The recovered embedded resources can be categorized into three functional groups:

Cross-Platform Memory Access

These resources are used to read the memory of running processes. While keys and tokens stored in ordinary files can often be discovered through file inspection, CI/CD runners and development tools frequently keep sensitive values temporarily in memory during execution. The attacker embedded memory-access utilities for Linux, Windows, and macOS to maximize the likelihood of extracting these transient secrets from process memory across different operating systems.

CZ.bin — Linux /proc/<pid>/mem memory dump

SHA-256:fb174de58e6825fed16de26d74ffbcacd74d371951e3064db51cfd700146d86f

UO.bin — Windows ReadProcessMemory memory dump

SHA-256:a150985aac1847e4a2e198f7ecccbbbc9443840699efd5a7654a006d61e1288e

VO.bin — macOS task_for_pid / mach_vm_region memory dump

SHA-256:aab0659e13fa2a8e482139b97ae523aacec91a42b5f125a7b0952bf57c3ac864

Persistence Configuration

These resources are designed to establish persistence mechanisms. In other words, even after the initial npm installation process has completed, the attacker aims to ensure that the malicious code can be executed again when the developer later opens a project, launches an editor, enters a Claude Code session, or logs back into the system. Accordingly, these resources target both project-level configurations and user-level auto-start mechanisms. Project-level configurations provide greater stealth, while system-level services are more suitable for long-term execution.

S8.bin — Claude Code SessionStart hook configuration

SHA-256:9566275be80af10b8c6be1d47bfcfdbe5590f472b1a9abd85bad24e0a9a7a891

EZ.bin — VS Code folderOpen task configuration

SHA-256:927387d0cfac1118df4b383decc2ea6ba49c9d2f98b47098bcbcba1efc026e1f

RZ.bin — kitty-monitor systemd / LaunchAgent installation script

SHA-256:bdcdae644bdf6285d01a986e1b8feb7ec4060e2c7d5f5e2609c16718922b7944

jZ.bin — gh-token-monitor systemd / LaunchAgent installation script

SHA-256:c5443b06aeb12dbf16046f9a8c9446d30e22655110e1e06919406d6f01a14ac5

C2 and Propagation

These embedded resources are used for subsequent command-and-control operations and repository secret exfiltration.

After decryption, YZ is a GitHub commit search monitor that periodically searches for commit messages matching the format firedalazer <base64-url>.<signature>. After validating the signature, it downloads and executes remote Python content.

After decryption, zZ is a GitHub Actions workflow template named Run Copilot, which writes ${{ toJSON(secrets) }} into format-results.txt and uploads the file as an artifact.

The former provides a mechanism for retrieving and executing follow-up tasks, while the latter provides a template for exfiltrating repository secrets through GitHub Actions artifacts. The actual workflow injection, execution monitoring, and artifact retrieval are handled by the supporting GitHub API logic contained within the main payload.

  • YZ.bin — GitHub commit search monitor (matches firedalazer)
    SHA-256:fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142
  • zZ.bin — Run Copilot GitHub Actions workflow
    SHA-256:3f3f42d072bd36860ab7bd7fb5e10ac0d22c741c13c89505ccd6ec0ea572eea7

Core Malicious Payload Capability Analysis

After completing all layers of deobfuscation, the samples ultimately release and execute the Core Malicious Payload. All analysis below focuses on the Core Malicious Payload modules and breaks them down across five stages: data acquisition, exfiltration, propagation, persistence, and evasion.

1. GitHub Actions Runner Memory Extraction

The samples embed memory-dumping scripts for Linux, Windows, and macOS, providing cross-platform memory extraction capabilities. The Linux implementation extracts memory by reading the target process’s /proc/<pid>/maps and /proc/<pid>/mem:

Press enter or click to view image in full size

The Core Malicious Payload’s active triggering logic specifically targets GitHub Actions Linux runners. When GITHUB_ACTIONS === “true” and RUNNER_OS === “Linux”, the code locates the Runner.Worker process and dumps its memory. It then extracts masked secrets matching the format:

"<name>":{"value":"<value>","isSecret":true}

Among the three samples, the verified active collection path focuses on Linux runners, although memory-extraction scripts for all three platforms are embedded.

2. Multi-Cloud and Local Developer Credential Harvesting

The Core Malicious Payload contains a systematic credential harvesting framework covering cloud providers, CI environments, local developer configurations, GitHub CLI credentials, password managers, and wallet files.

The cloud credential collection targets are as follows:

Press enter or click to view image in full size

The AWS module also contains logic related to ECS, IMDS (Instance Metadata Service), and STS WebIdentity.

Local developer credential harvesting covers the following targets:

Press enter or click to view image in full size

The password manager logic is implemented using runCommand(command, args) arrays rather than shell-string concatenation.

These credential collection modules cover a broad range of targets, from cloud platforms to local developer environments. The collected sensitive data is exfiltrated through the mechanisms described below.

3. GitHub API Exfiltration and Dead-Drop Mechanism

The Core Malicious Payload uses the GitHub API as its primary data exfiltration channel.

Requests spoof the User-Agent as:

python-requests/2.31.0

After validating the token’s x-oauth-scopes header (which must contain repo, public_repo, or workflow permissions), the payload performs exfiltration operations by:

  • Creating a repository (with a fixed description of Miasma: The Spreading Blight)
  • Base64-encoding stolen data
  • Writing the encoded data via PUT /repos/<owner>/<repo>/contents/results/<file>

In addition, the payload implements a dead-drop mechanism based on GitHub commit search. It retrieves C2 instructions by searching for the marker “thebeautifulmarchoftime “ (or “thebeautifulsnadsoftime”):

let result = await X9(“thebeautifulmarchoftime “, xZ);

The embedded resource YZ.bin is a standalone GitHub commit monitor that polls every 3600 seconds, searching for commit messages matching the format:

firedalazer <base64>.<signature>

After successful signature verification, it downloads and executes remote Python content. This forms an independent post-compromise control channel separate from the primary exfiltration mechanism.

The source code also contains an HTTP POST sender configuration targeting api.anthropic.com and v1/api endpoints. The configuration object’s noop field is set to true, meaning that under its default state the sender will not issue actual network requests. Therefore, static analysis can only confirm the existence of this code structure and cannot demonstrate active exfiltration through the Anthropic API.

4. GitHub Repository and Workflow Infection

The Core Malicious Payload is capable of manipulating repository git objects through the GitHub REST and GraphQL APIs:

GET /repos/<owner>/<repo>/git/refs/heads/<branch>

POST /repos/<owner>/<repo>/git/blobs

POST /repos/<owner>/<repo>/git/trees

POST /repos/<owner>/<repo>/git/commits

PATCH /repos/<owner>/<repo>/git/refs/heads/<branch>

createCommitOnBranch(input: …)

The malicious workflow constructed by the payload is named release and requests the id-token: write permission. It uses an OIDC (OpenID Connect) flow to obtain an npm publishing token. The OIDC path relies on the environment variables ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL, with the audience set to npm:registry.npmjs.org. At the source-code level, it can be confirmed that the payload is capable of injecting workflows into GitHub repositories and obtaining publishing privileges through OIDC/npm trusted publishing.

In addition to workflow injection through git refs, the payload embeds a more covert secrets exfiltration mechanism. A GitHub Actions workflow disguised as Run Copilot writes ${{ toJSON(secrets) }} into format-results.txt and uploads it as an artifact. Compared with directly writing secrets into repository content, this approach relies on workflow artifacts for data transfer, making the exported secrets less visible during routine code diff reviews.

5. Run Copilot Workflow Uses Artifacts to Transfer Secrets

The embedded resource zZ.bin is a GitHub Actions workflow disguised as Copilot. It writes ${{ toJSON(secrets) }} into format-results.txt and uploads the file as an artifact.

The associated GitHub API workflow includes:

  • Creating/updating a temporary branch
  • Writing the workflow blob
  • Waiting for workflow execution
  • Downloading the artifact ZIP
  • Reading format-results.txt
  • Deleting the workflow run and temporary branch

Relevant hunting keywords include:

Run Copilot

VARIABLE_STORE

format-results

chore/add-codeql-static-analysis

.github/workflows/codeql.yml

6. npm Self-Propagation

The Core Malicious Payload contains two independent npm publishing and propagation paths.

npm Token Path:

The payload enumerates the current user’s npm tokens through:

GET /-/npm/v1/tokens

It filters tokens where bypass_2fa === true and package write permissions are available, then uses those tokens for automated publishing. bypass_2fa is a token metadata field rather than a publish request parameter.

GitHub Actions OIDC Path:

The payload reads the ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL environment variables, requests an OIDC token with the audience set to npm:registry.npmjs.org, and exchanges it for publishing privileges through the npm OIDC token exchange interface.

The process used to contaminate a target tarball is: unpack → write a malicious index.js → modify package.json:

Press enter or click to view image in full size

A distinction should be made between two entry paths: the three locally uploaded samples analyzed in this report use preinstall: “node index.js” themselves. In this case, the installation environment does not need Bun to be preinstalled, making Node.js a more stealthy initial entry point. When self-propagating to contaminate other packages, however, the payload writes preinstall: “bun run index.js” and adds a Bun dependency. This is because the later stages of the Core Malicious Payload rely on APIs provided by the Bun runtime (such as Bun.gunzipSync and Bun.file), making it necessary to ensure that Bun is available in the target environment during self-propagation.

7. Persistence Mechanisms

The Core Malicious Payload implements four persistence mechanisms, covering both project directories and system-level auto-start locations.

Claude Code SessionStart hook:The embedded resource S8.bin writes a SessionStart hook into .claude/settings.json, causing node .claude/setup.mjs to execute automatically whenever a Claude Code session starts. The payload also writes .claude/setup.mjs and .claude/index.js (with the path constructed as “.claude/” + M0, where M0 = “index.js”).

VS Code folderOpen task:The embedded resource EZ.bin writes a folderOpen task into .vscode/tasks.json, causing the same script to execute automatically whenever an infected project folder is opened. It also writes .vscode/setup.mjs.

kitty-monitor(systemd / LaunchAgent):The embedded resource RZ.bin installs a persistence service. Files are distributed across ~/.local/share/kitty/cat.py, ~/.config/systemd/user/kitty-monitor.service (Linux), and ~/Library/LaunchAgents/com.user.kitty-monitor.plist (macOS). The payload creates a /tmp/kitty-<random> directory, writes YZ.bin (the GitHub commit monitor) into cat.py, and installs it through RZ.bin.

gh-token-monitor(systemd / LaunchAgent):The embedded resource jZ.bin installs a GitHub token monitoring service. Files are distributed across ~/.local/bin/gh-token-monitor.sh, the ~/.config/gh-token-monitor/ directory, and the corresponding systemd / LaunchAgent locations. The monitor checks whether GitHub tokens return 40x status codes and whether the metadata of the npm package @cap-js/openapi@1.4.1 appears abnormal. When triggered, it executes a handler:

Press enter or click to view image in full size

This means that when the monitor observes GitHub API responses with 40x status codes — for example, when a token has been revoked, expired, or enters an abnormal permission state — the malicious script executes the supplied handler. In the three samples analyzed in this report, the recovered handler was rm -rf ~/; rm -rf ~/Documents. During incident response, tokens should not be revoked directly on hosts that may still be running the payload. Instead, responders should first isolate the host, remove persistence mechanisms and active processes, and then rotate credentials from a clean environment.

Press enter or click to view image in full size

8. Harden-Runner / StepSecurity Evasion

The Core Malicious Payload contains built-in detection and disruption logic targeting StepSecurity Harden-Runner and bypasses CI/CD protections through the following steps:

  1. Check whether the Docker socket /var/run/docker.sock is available;
  2. Enumerate Docker containers and match the keywords harden-runner or stepsecurity in container names or images;
  3. Terminate matching containers via POST /containers/<id>/kill;
  4. Create a privileged Alpine container and modify sudoers to runner ALL=(ALL) NOPASSWD:ALL;
  5. Write invalid hostname resolutions for StepSecurity-related domains into /etc/hosts;
  6. Overwrite /etc/resolv.conf with 8.8.8.8 and 1.1.1.1.

This evasion logic indicates that the samples were specifically adapted for CI/CD environments protected by StepSecurity.

9. EDR / Security Product Detection, Environment Awareness, and Evasion

The Core Malicious Payload detects multiple EDR (Endpoint Detection and Response) and security products by checking process names and installation paths:

Press enter or click to view image in full size

The payload also contains regional evasion logic. It checks the LC_ALL, LC_MESSAGES, LANGUAGE, and LANG environment variables and converts their values to lowercase. If a value begins with ru, execution is skipped. CI environment detection supports GitHub Actions, GitLab CI, Travis CI, CircleCI, Jenkins, AWS CodeBuild, Buildkite, AppVeyor, Bitbucket, Drone, TeamCity, Cirrus CI, and others. Runtime state markers include tmp.0987654321.lock, __IS_DAEMON (marks detached daemon subprocesses), SKIP_DOMAIN (skips the domain sender path), /tmp/kitty-*, cat.py, and /var/tmp/.gh_update_state.

Impact Analysis

Based on the capabilities observed in the source code, the impact of these three samples is not limited to a one-time execution during npm installation. The actual risk can be divided into four layers:

Developer Host Layer. The samples collect environment variables, .npmrc, .pypirc, SSH keys, Docker configurations, .env files, GitHub CLI tokens, password manager data, and wallet files. They also maintain post-compromise execution capabilities through Claude Code, VS Code, systemd user services, or macOS LaunchAgents.

CI/CD Runner Layer. The samples identify GitHub Actions Linux runners, read the memory of the Runner.Worker process, and extract masked secrets. They also contain StepSecurity Harden-Runner evasion logic designed to disrupt or bypass CI/CD security controls.

GitHub Organization and Repository Layer. The samples can use the GitHub API to create repositories, write to contents/results/, manipulate git refs/blobs/trees/commits, inject malicious workflows, and exfiltrate secrets through the Run Copilot workflow and artifacts.

npm Ecosystem Propagation Layer. The samples can identify npm tokens that possess package write permissions and satisfy bypass_2fa === true. They can also obtain publishing privileges through GitHub Actions OIDC and npm trusted publishing workflows. The payload then downloads target tarballs, injects a malicious loader, modifies preinstall, adds a Bun dependency, increments the patch version, and republishes the package, thereby establishing an npm self-propagation chain.

Summary

The source code evidence from the three samples shows that these malicious packages are not simple installation-time credential-stealing scripts, but rather a combination of a multi-stage loader and a fully featured implant. While the outer packaging is randomized on a per-package basis, both the Bun Runtime Bootstrapper and the Core Malicious Payload remain identical. The main implant covers multiple stages, including credential harvesting, CI secret extraction, GitHub/npm propagation, persistence, and defensive evasion.

Highly stealthy initial access design.

Rather than embedding malicious logic directly into application code, the attacker mounts an obfuscated loader through npm lifecycle scripts. The loader itself is primarily responsible for decrypting and executing the embedded payload, making it difficult to uncover the actual malicious capabilities through application source code review alone.

A deeply layered deobfuscation chain.

The malicious payload is protected by five layers of packaging: numeric array + ROT letter substitution, AES-128-GCM encryption, obfuscator.io obfuscation, B5 custom string encryption, and an AES-256-GCM + gzip embedded layer. The keys and parameters used at each layer can vary independently across packages, making large-scale detection based on static signatures significantly more difficult.

Comprehensive organization-level attack capabilities.

The implant includes capabilities for GitHub Actions Runner memory extraction, multi-cloud and local credential harvesting, GitHub API exfiltration and dead-drop mechanisms, GitHub repository and workflow infection, npm self-propagation, persistence, and defensive evasion. Based on the source code structure, it already contains code paths capable of expanding from a single installation event into repositories, CI/CD environments, and npm publishing pipelines. The actual scope of propagation still requires validation through installation logs, repository audits, and platform-side telemetry.

What can be confirmed from the source code evidence is that all three samples are automatically triggered through preinstall and decrypt and execute the same primary implant. However, the manner in which the attacker initially obtained access during the real-world incident cannot be proven solely from these three tgz samples.

Remediation Recommendations

  1. Identify and remove the malicious versions from project dependencies, lockfiles, private registry caches, and build caches.
  2. Review installation logs for indicators such as preinstall, node index.js, bun run, /tmp/p*.js, and tmp.0987654321.lock.
  3. Do not revoke tokens directly on potentially compromised hosts that may still be running the payload. First isolate affected hosts, remove active processes and persistence mechanisms, and then rotate GitHub, npm, cloud provider, Kubernetes, Vault, SSH, Docker registry, and password manager credentials from a clean environment.
  4. Review recent GitHub repository branches, commits, workflows, artifacts, and newly created repositories. Pay particular attention to the keywords Run Copilot, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml, and OIDC_PACKAGES.
  5. Check whether the following project files have been newly created or modified: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, and .vscode/setup.mjs.
  6. Check for user-level persistence artifacts: files related to ~/.local/share/kitty/cat.py, ~/.config/systemd/user/kitty-monitor.service, ~/Library/LaunchAgents/com.user.kitty-monitor.plist, and gh-token-monitor.
  7. Review npm publish history to determine whether unauthorized patch versions have been published. Also audit npm token metadata, with particular attention to tokens that can bypass 2FA (Two-Factor Authentication) and possess package write permissions.
  8. Perform integrity audits on downstream artifacts built within affected environments.

IOC

Malicious Files

filename: redhat-cloud-services-frontend-components-config-6.11.3.tgz

MD5: 633ad8849a59e2bfb7a0fe589e816a07

SHA1: 675294612f455fe6a9acb195f0cbe3687d8e2e34

SHA256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060

filename: redhat-cloud-services-types-3.6.1.tgz

MD5: 9e6c5af01438b52c9a411686c1f1b8ff

SHA1: 88d098c8d96e9ae17550e9798c3b62c420464b8c

SHA256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558

filename: redhat-cloud-services-rule-components-4.7.2.tgz

MD5: f1ffdbf5e639899f26a6ebab2eec408d

SHA1: f3c5c21274045ae02fef11e931de6dcf8462a067

SHA256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f

SHA256

ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6

0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35

Malicious Dependencies

npm:@redhat-cloud-services/topological-inventory-client@3.0.10

npm:@redhat-cloud-services/topological-inventory-client@3.0.11

npm:@redhat-cloud-services/topological-inventory-client@3.0.13

npm:@redhat-cloud-services/compliance-client@4.0.3

npm:@redhat-cloud-services/compliance-client@4.0.4

npm:@redhat-cloud-services/compliance-client@4.0.6

npm:@redhat-cloud-services/rbac-client@9.0.3

npm:@redhat-cloud-services/rbac-client@9.0.4

npm:@redhat-cloud-services/rbac-client@9.0.6

npm:@redhat-cloud-services/insights-client@4.0.4

npm:@redhat-cloud-services/insights-client@4.0.5

npm:@redhat-cloud-services/insights-client@4.0.7

npm:@redhat-cloud-services/frontend-components@7.7.2

npm:@redhat-cloud-services/frontend-components@7.7.3

npm:@redhat-cloud-services/frontend-components@7.7.5

npm:@redhat-cloud-services/frontend-components-utilities@7.4.1

npm:@redhat-cloud-services/frontend-components-utilities@7.4.2

npm:@redhat-cloud-services/frontend-components-utilities@7.4.4

npm:@redhat-cloud-services/remediations-client@4.0.4

npm:@redhat-cloud-services/remediations-client@4.0.5

npm:@redhat-cloud-services/remediations-client@4.0.7

npm:@redhat-cloud-services/frontend-components-notifications@6.9.2

npm:@redhat-cloud-services/frontend-components-notifications@6.9.3

npm:@redhat-cloud-services/frontend-components-notifications@6.9.5

npm:@redhat-cloud-services/patch-client@4.0.4

npm:@redhat-cloud-services/patch-client@4.0.5

npm:@redhat-cloud-services/patch-client@4.0.7

npm:@redhat-cloud-services/host-inventory-client@5.0.3

npm:@redhat-cloud-services/host-inventory-client@5.0.4

npm:@redhat-cloud-services/host-inventory-client@5.0.6

npm:@redhat-cloud-services/rule-components@4.7.2

npm:@redhat-cloud-services/rule-components@4.7.3

npm:@redhat-cloud-services/rule-components@4.7.5

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.2

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.4

npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.6

npm:@redhat-cloud-services/notifications-client@6.1.4

npm:@redhat-cloud-services/notifications-client@6.1.5

npm:@redhat-cloud-services/notifications-client@6.1.7

npm:@redhat-cloud-services/sources-client@3.0.10

npm:@redhat-cloud-services/sources-client@3.0.11

npm:@redhat-cloud-services/sources-client@3.0.13

npm:@redhat-cloud-services/integrations-client@6.0.4

npm:@redhat-cloud-services/integrations-client@6.0.5

npm:@redhat-cloud-services/integrations-client@6.0.7

npm:@redhat-cloud-services/frontend-components-config@6.11.3

npm:@redhat-cloud-services/frontend-components-config@6.11.4

npm:@redhat-cloud-services/frontend-components-config@6.11.6

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.2

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.3

npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.5

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.1

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.2

npm:@redhat-cloud-services/hcc-pf-mcp@0.6.4

npm:@redhat-cloud-services/frontend-components-remediations@4.9.2

npm:@redhat-cloud-services/frontend-components-remediations@4.9.3

npm:@redhat-cloud-services/frontend-components-remediations@4.9.5

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.1

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.2

npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.4

npm:@redhat-cloud-services/javascript-clients-shared@2.0.8

npm:@redhat-cloud-services/javascript-clients-shared@2.0.9

npm:@redhat-cloud-services/javascript-clients-shared@2.0.11

npm:@redhat-cloud-services/quickstarts-client@4.0.11

npm:@redhat-cloud-services/quickstarts-client@4.0.12

npm:@redhat-cloud-services/quickstarts-client@4.0.14

npm:@redhat-cloud-services/config-manager-client@5.0.4

npm:@redhat-cloud-services/config-manager-client@5.0.5

npm:@redhat-cloud-services/config-manager-client@5.0.7

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.1

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.2

npm:@redhat-cloud-services/hcc-feo-mcp@0.3.4

npm:@redhat-cloud-services/entitlements-client@4.0.11

npm:@redhat-cloud-services/entitlements-client@4.0.12

npm:@redhat-cloud-services/entitlements-client@4.0.14

npm:@redhat-cloud-services/tsc-transform-imports@1.2.2

npm:@redhat-cloud-services/tsc-transform-imports@1.2.4

npm:@redhat-cloud-services/tsc-transform-imports@1.2.6

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.1

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.2

npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.4

npm:@redhat-cloud-services/frontend-components-testing@1.2.1

npm:@redhat-cloud-services/frontend-components-testing@1.2.2

npm:@redhat-cloud-services/frontend-components-testing@1.2.4

npm:@redhat-cloud-services/types@3.6.1

npm:@redhat-cloud-services/types@3.6.2

npm:@redhat-cloud-services/types@3.6.4

npm:@redhat-cloud-services/chrome@2.3.1

npm:@redhat-cloud-services/chrome@2.3.2

npm:@redhat-cloud-services/chrome@2.3.4

npm:@redhat-cloud-services/frontend-components-translations@4.4.1

npm:@redhat-cloud-services/frontend-components-translations@4.4.2

npm:@redhat-cloud-services/frontend-components-translations@4.4.4

npm:@redhat-cloud-services/vulnerabilities-client@2.1.8

npm:@redhat-cloud-services/vulnerabilities-client@2.1.9

npm:@redhat-cloud-services/vulnerabilities-client@2.1.11

About SlowMist

SlowMist is a threat intelligence firm focused on blockchain security, established in January 2018. The firm was started by a team with over ten years of network security experience to become a global force. Our goal is to make the blockchain ecosystem as secure as possible for everyone. We are now a renowned international blockchain security firm that has worked on various well-known projects such as HashKey Exchange, OSL, MEEX, BGE, BTCBOX, Bitget, BHEX.SG, OKX, Binance, HTX, Amber Group, Crypto.com, etc.

SlowMist offers a variety of services that include but are not limited to security audits, threat information, defense deployment, security consultants, and other security-related services. We also offer AML (Anti-money laundering) software, MistEye (Security Monitoring), SlowMist Hacked (Crypto hack archives), FireWall.x (Smart contract firewall) and other SaaS products. We have partnerships with domestic and international firms such as Akamai, BitDefender, RC², TianJi Partners, IPIP, etc. Our extensive work in cryptocurrency crime investigations has been cited by international organizations and government bodies, including the United Nations Security Council and the United Nations Office on Drugs and Crime.

By delivering a comprehensive security solution customized to individual projects, we can identify risks and prevent them from occurring. Our team was able to find and publish several high-risk blockchain security flaws. By doing so, we could spread awareness and raise the security standards in the blockchain ecosystem.

--

--

SlowMist
SlowMist

Written by SlowMist

SlowMist is a Blockchain security firm established in 2018, providing services such as security audits, security consultants, red teaming, and more.