Sploitus

Exploit for POC-keyv-and-cacheable-npm-Package

githubexploit Β· 2026-08-04

Exploit Code

README394 lines
## https://sploitus.com/exploit?id=8A58D5FD-419D-55A7-B881-B7A876719CDD
# ChainDrop npm Supply Chain Attack β€” PoC Scanner & Exploit

> **keyv / cacheable npm Package Hijack** β€” Shai-Hulud Credential-Stealing Worm
> Discovered: **August 4, 2026** | Attributed to: **Wiz Research**

---

## Table of Contents

- [Overview](#overview)
- [Attack Summary](#attack-summary)
- [Indicators of Compromise (IOCs)](#indicators-of-compromise-iocs)
- [Architecture & Attack Flow](#architecture--attack-flow)
- [File Structure](#file-structure)
- [Installation](#installation)
- [Step-by-Step Usage](#step-by-step-usage)
- [Detection Capabilities](#detection-capabilities)
- [Mitigation](#mitigation)
- [References](#references)
- [Disclaimer](#disclaimer)
- [License](#license)

---

## Overview

On **August 4, 2026**, a massive npm supply chain attack dubbed **ChainDrop** was discovered by Wiz Research. The attack compromised the GitHub account of the maintainer behind `keyv`, `cacheable`, `flat-cache`, `file-entry-cache`, and related packages in the `cacheable` ecosystem. The attacker published malicious versions containing the **Shai-Hulud** credential-stealing worm, which self-propagated by stealing npm tokens from CI/CD environments and publishing further compromised packages.

This repository provides a **proof-of-concept scanner and forensic analyzer** to detect and analyze ChainDrop-compromised npm packages across your GitHub organization and individual packages.

### Scale of Attack

| Metric | Value |
|--------|-------|
| **Compromised packages** | 400+ unique packages |
| **Malicious versions** | 1,300+ |
| **Affected organizations** | 14+ (scoped packages) |
| **Monthly downloads affected** | ~2 billion |
| **C2 mechanism** | Ethereum smart contract (`StringListStore`) |
| **Malware family** | Shai-Hulud (Mini variant) |
| **Exfil domain** | `npm-cache[.]com` |

---

## Attack Summary

### Timeline

1. **GitHub maintainer account compromised** β€” attacker gains access to the `keyv`/`cacheable` maintainer's GitHub account
2. **Malicious commits pushed** β€” IDE persistence payloads introduced to the `keyv` repository
3. **Malicious versions published** β€” `keyv@6.0.0` and other packages published to npm with Shai-Hulud worm
4. **Self-propagation** β€” worm steals npm tokens from CI/CD environments of downstream projects
5. **Widespread infection** β€” stolen tokens used to publish compromised versions of 400+ additional packages

### How the Malware Works

```
npm install compromised-package
        β”‚
        β–Ό
preinstall hook: node setup.mjs
        β”‚
        β–Ό
Shai-Hulud worm activates:
  1. Resolves C2 domain via Ethereum smart contract (eth_call β†’ StringListStore)
  2. Steals credentials: .npmrc, .gitconfig, AWS keys, GitHub tokens, SSH keys
  3. Exfiltrates to npm-cache[.]com via HTTPS (User-Agent: Bun/1.3.13)
  4. Drops persistence: Math_Symbol.js, math_init.js
  5. Self-propagates using stolen npm tokens
```

### C2 Infrastructure

| Type | Value |
|------|-------|
| **Exfil domain** | `npm-cache[.]com` (Cloudflare: 104.21.35.216) |
| **Backup domains** | `pypi-get[.]com`, `js-mirror[.]com` |
| **ETH RPC (C2 resolution)** | `eth-mainnet.nodereal[.]io`, `go.getblock[.]io`, `eth.llamarpc[.]com` |
| **Smart contract** | `StringListStore` (Ethereum) |
| **User-Agent** | `Bun/1.3.13` |
| **Intimidation string** | `IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients` |
| **GitHub repo desc** | `Shai-Hulud: Here We Go Again` |

---

## Indicators of Compromise (IOCs)

### Malicious Files

| File | SHA1 |
|------|------|
| `setup.mjs` | `686aa40d0fc2...` |
| `Math_Symbol.js` | `35a672cf34b996b91f3e1c28cbf3a05a37e036e4` |
| `math_init.js` | β€” |

### Domains

- `npm-cache[.]com` β€” Exfil domain (104.21.35[.]216, Cloudflare)
- `pypi-get[.]com`
- `js-mirror[.]com`
- `eth-mainnet.nodereal[.]io` β€” ETH RPC (35.175.164[.]77, Amazon)
- `go.getblock[.]io` β€” ETH RPC (185.44.207.215)
- `eth.llamarpc[.]com` β€” ETH RPC (172.67.167.200, Cloudflare)

### File Artifacts

- `/tmp/bun-dl-*/`
- `node_modules/keyv/Math_Symbol.js`

### User-Agents

- `Bun/1.3.13`

### Attribution Strings

- `IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients`
- `Shai-Hulud: Here We Go Again`

---

## Architecture & Attack Flow

### Component Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        chaindrop-scanner                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  scan.py             β”‚     β”‚  exploit.py                           β”‚   β”‚
β”‚  β”‚  (Org Scanner)       β”‚     β”‚  (Forensic Package Analyzer)          β”‚   β”‚
β”‚  β”‚                      β”‚     β”‚                                       β”‚   β”‚
β”‚  β”‚  β€’ Load IOCs        β”‚     β”‚  β€’ Download tarball from npm          β”‚   β”‚
β”‚  β”‚  β€’ GitHub Code      β”‚     β”‚  β€’ Extract & inspect (safe/static)    β”‚   β”‚
β”‚  β”‚    Search API       β”‚     β”‚  β€’ Known file detection               β”‚   β”‚
β”‚  β”‚  β€’ package.json     β”‚     β”‚  β€’ Hash matching (SHA1)               β”‚   β”‚
β”‚  β”‚    version extract  β”‚     β”‚  β€’ C2 domain/IP scan                  β”‚   β”‚
β”‚  β”‚  β€’ Semver safety    β”‚     β”‚  β€’ ETH smart contract patterns        β”‚   β”‚
β”‚  β”‚    heuristic        β”‚     β”‚  β€’ Credential theft patterns          β”‚   β”‚
β”‚  β”‚  β€’ JSON/console     β”‚     β”‚  β€’ Obfuscation detection              β”‚   β”‚
β”‚  β”‚    reporting        β”‚     β”‚  β€’ Install hook analysis              β”‚   β”‚
β”‚  β”‚                      β”‚     β”‚  β€’ Risk scoring & verdict            β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚           β”‚                                    β”‚                          β”‚
β”‚           β–Ό                                    β–Ό                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  compromised_        β”‚     β”‚  Forensic JSON Report                 β”‚   β”‚
β”‚  β”‚  packages.txt        β”‚     β”‚  β€’ Package metadata                   β”‚   β”‚
β”‚  β”‚  (IOC list)          β”‚     β”‚  β€’ File listing + hashes              β”‚   β”‚
β”‚  β”‚                      β”‚     β”‚  β€’ Findings by severity               β”‚   β”‚
β”‚  β”‚  32+ non-scoped      β”‚     β”‚  β€’ Risk score (0-500+)                β”‚   β”‚
│  │  packages            │     │  ‒ Verdict (CLEAN→MALICIOUS)          │   │
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

### Attack Flow Diagram

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Attacker │────▢│ Compromised     │────▢│ npm Registry          β”‚
β”‚          β”‚     β”‚ GitHub Account  β”‚     β”‚ (malicious versions)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                     β”‚
                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Victim CI/CD or Developer Machine                               β”‚
β”‚                                                                  β”‚
β”‚  npm install keyv@6.0.0                                          β”‚
β”‚       β”‚                                                          β”‚
β”‚       β–Ό                                                          β”‚
β”‚  preinstall β†’ node setup.mjs                                     β”‚
β”‚       β”‚                                                          β”‚
β”‚       β”œβ”€β”€β–Ά eth_call β†’ StringListStore β†’ resolve npm-cache.com   β”‚
β”‚       β”œβ”€β”€β–Ά Steal .npmrc token                                    β”‚
β”‚       β”œβ”€β”€β–Ά Steal ~/.gitconfig                                    β”‚
β”‚       β”œβ”€β”€β–Ά Steal AWS/SSH/K8s credentials                         β”‚
β”‚       β”œβ”€β”€β–Ά Exfiltrate to npm-cache.com                           β”‚
β”‚       β”œβ”€β”€β–Ά Drop Math_Symbol.js persistence                       β”‚
β”‚       └──▢ Publish new malicious packages with stolen token      β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

### Mermaid Diagram

```mermaid
graph TD
    A[Attacker] --> B[Compromised GitHub Account]
    B --> C[Malicious npm Packages]
    C --> D[npm Registry]
    D --> E[Victim CI/CD]
    E --> F[preinstall: node setup.mjs]

    F --> G1[eth_call β†’ StringListStore]
    G1 --> G2[Resolve C2: npm-cache.com]

    F --> H1[Steal .npmrc token]
    F --> H2[Steal .gitconfig]
    F --> H3[Steal AWS/SSH/K8s keys]
    F --> H4[Steal GitHub PATs]

    H1 --> I[Exfiltrate to npm-cache.com]
    H2 --> I
    H3 --> I
    H4 --> I

    I --> J[Drop Math_Symbol.js]
    J --> K[Publish new malicious packages]
    K --> D

    subgraph "ChainDrop Scanner"
        S1[scan.py: GitHub Org Scanner]
        S2[exploit.py: Forensic Analyzer]
        S3[compromised_packages.txt]
    end

    S3 --> S1
    S3 --> S2
    S1 --> L[Detect compromised deps in org]
    S2 --> M[Analyze individual packages]
```

---

## File Structure

```
chaindrop-scanner/
β”œβ”€β”€ scan.py                    # GitHub org scanner β€” cross-references IOCs against repos
β”œβ”€β”€ exploit.py                 # Forensic package analyzer β€” deep inspection of npm packages
β”œβ”€β”€ compromised_packages.txt   # Known compromised package list (32+ non-scoped)
β”œβ”€β”€ requirements.txt           # Python dependencies (stdlib-only, no install needed)
β”œβ”€β”€ README.md                  # This file
└── LICENSE                    # MIT License
```

---

## Installation

### Prerequisites

- **Python 3.8+** (stdlib only β€” zero external dependencies)
- GitHub token (optional, for higher API rate limits when scanning orgs)

### Clone

```bash
git clone git@github.com:sam00/POC-keyv-and-cacheable-npm-Package.git
cd chaindrop-scanner
```

No `pip install` required β€” both tools use only Python standard library.

---

## Step-by-Step Usage

### Step 1: Scan Your GitHub Organization

Cross-reference all known ChainDrop-compromised packages against your org's repositories:

```bash
# Basic scan (unauthenticated, ~10 req/min)
python3 scan.py --org your-github-org

# With GitHub token (recommended, 30 req/min)
export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
python3 scan.py --org your-github-org

# Save results as JSON
python3 scan.py --org your-github-org --json scan_results.json

# Include scoped packages (@servicetitan/*, @ornikar/*, etc.)
python3 scan.py --org your-github-org --include-scopes

# Use custom package list
python3 scan.py --org your-github-org --packages my_custom_list.txt
```

### Step 2: Analyze a Suspicious Package

Download and forensically analyze a specific npm package for ChainDrop IOCs:

```bash
# Analyze from npm registry
python3 exploit.py --package keyv --version 6.0.0

# Analyze a local tarball
python3 exploit.py --tarball ./suspicious-package-1.0.0.tgz

# Save forensic report as JSON
python3 exploit.py --package keyv --version 6.0.0 --json forensic_report.json

# Extract package contents for manual review
python3 exploit.py --package keyv --version 6.0.0 --extract-to ./evidence/
```

### Step 3: Interpret Results

**Scanner output:**
- `[CLEAN]` β€” Package not found in any repository. Safe.
- `FOUND` β€” Package appears in a `package.json`. Check the version:
  - `keyv@^4.5.4` β†’ **safe** (major bump `6.0.0` excluded by `^`)
  - `keyv@6.0.0` β†’ **vulnerable** (exact match to malicious version)

**Forensic analyzer risk scores:**

| Score | Verdict |
|-------|---------|
| 0 | CLEAN β€” No indicators found |
| 1–19 | LOW RISK β€” Minor indicators only |
| 20–49 | SUSPICIOUS β€” Some indicators found |
| 50–99 | SUSPICIOUS β€” Multiple high-severity indicators |
| 100+ | MALICIOUS β€” Confirmed ChainDrop indicators |

---

## Detection Capabilities

### Scanner (`scan.py`)

| Feature | Description |
|---------|-------------|
| **GitHub Code Search** | Searches all repos in an org for compromised packages |
| **package.json parsing** | Extracts version specifiers from all dependency sections |
| **Semver heuristic** | Determines if version ranges include malicious versions |
| **Scoped packages** | Optional scanning of scoped package families |
| **JSON reporting** | Machine-readable output for CI/CD integration |

### Forensic Analyzer (`exploit.py`)

| Category | Patterns Detected |
|----------|------------------|
| **Known files** | `setup.mjs`, `Math_Symbol.js`, `math_init.js` |
| **Known hashes** | SHA1: `35a672cf...`, `686aa40d...` |
| **C2 domains** | `npm-cache.com`, `pypi-get.com`, `js-mirror.com` |
| **C2 IPs** | 104.21.35.216, 35.175.164.77, 185.44.207.215, 172.67.167.200 |
| **ETH RPC** | `eth-mainnet.nodereal.io`, `go.getblock.io`, `eth.llamarpc.com` |
| **ETH C2** | `eth_call`, `StringListStore`, ETH addresses (0x...40) |
| **User-Agent** | `Bun/1.3.13` |
| **Credential theft** | GitHub PATs (ghp_/gho_/ghs_), npm tokens, AWS keys, K8s secrets, Vault tokens, Stripe/Slack/Twilio/Azure/GCP keys, process.env, .npmrc, .gitconfig |
| **Obfuscation** | Packed functions, hex escapes, unicode escapes, base64+eval chains, dynamic Function() |
| **Install hooks** | `preinstall`/`postinstall` scripts, suspicious commands (curl, wget, eval, exec, spawn) |

---

## Mitigation

1. **Identify and remove** affected package versions from development, build, and CI/CD environments
2. **Treat affected systems as compromised** β€” rebuild if malicious packages were installed
3. **Rotate all exposed credentials**:
   - npm tokens
   - GitHub personal access tokens
   - AWS access keys
   - SSH keys
   - Kubernetes secrets
   - Terraform credentials
   - CI/CD environment variables
4. **Audit cloud and source code environments** for unauthorized access
5. **Block IOCs** at network/firewall level (domains, IPs listed above)
6. **Enable dependency pinning** and lockfile validation (`package-lock.json`, `yarn.lock`)
7. **Use `--ignore-scripts`** during `npm install` in CI/CD where possible
8. **Monitor for** the published IOCs, including domains, file artifacts, and attribution strings

---

## References

- [Wiz Blog β€” keyv and cacheable npm Package Hijacked in Supply Chain Attack](https://www.wiz.io/blog/keyv-and-cacheable-npm-supply-chain-attack)
- [StepSecurity β€” ChainDrop npm Worm](https://www.stepsecurity.io/blog/chaindrop-npm-worm)
- [BleepingComputer β€” Massive ChainDrop npm Supply Chain Attack](https://www.bleepingcomputer.com/news/security/massive-chaindrop-npm-supply-chain-attack-infects-hundreds-of-packages/)
- [Aikido Security β€” keyv/cacheable npm Supply Chain Attack Analysis](https://www.aikido.dev/blog/keyv-cacheable-npm-supply-chain-attack)
- [Wiz Research IOCs β€” Full compromised packages CSV](https://github.com/wiz-sec-public/wiz-research-iocs/blob/main/reports/keyv-packages.csv)
- [Socket.dev β€” ChainDrop Advisory](https://socket.dev/blog)

---

## Disclaimer

This proof-of-concept scanner and forensic analyzer is provided for **educational and authorized security testing purposes only**. Use this tool only against systems and organizations you own or have explicit written authorization to test.

The authors and contributors are not responsible for any misuse or damage caused by this software.

---

## License

MIT License β€” see [LICENSE](LICENSE) for details.