> ## Content Index
> Fetch the complete content index at: https://f4n6.co.uk/llms.txt
> Use this file to discover other available public pages before exploring further.

# Don't Revoke That Token Yet: Inside the keyv/cacheable npm Worm
- URL: https://f4n6.co.uk/security-feed/dont-revoke-that-token-yet-inside-the-keyv-cacheable-npm-worm/
- Published: 2026-08-05T21:22:18.000Z
- Updated: 2026-08-05T21:22:18.000Z
- Author: Jeff Davies
- Tags: #security-feed

## 1\. Executive summary

On August 4, 2026, an attacker compromised the maintainer account for the widely used `keyv` and `cacheable` npm namespaces and published trojanized releases containing a self-propagating worm (tracked as CHAINDROP/Shai-Hulud). The malicious packages use a `preinstall` hook to execute a payload that steals cloud, Vault, Kubernetes, and npm credentials, and then leverages the stolen npm tokens to automatically backdoor additional packages. The campaign has impacted over 400–868 packages (figures vary by vendor reporting) and introduces a dead-man's switch that triggers an unknown, attacker-controlled payload if compromised GitHub tokens are revoked. EMEA financial services with heavy Node.js/JavaScript dependencies are at significant risk of credential compromise and lateral movement via CI/CD environments.

## 2\. Regulatory framing

No specific DORA/NIS2 article is directly engaged by this item.

## 3\. Technical analysis & attack chain

This item is a threat-campaign involving a self-propagating npm supply chain worm. The attack chain operates as follows:

1. **Initial Compromise:** The attacker took over the maintainer account for the `keyv` and `cacheable` npm namespaces. The first malicious release, `keyv@6.0.0`, was published at 09:35 UTC on August 4, 2026.
2. **Execution via `preinstall`:** The malicious `package.json` files contain a `preinstall` hook: `"scripts": { "preinstall": "node setup.mjs" }`. This executes automatically upon `npm install` before installation completes.
3. **Secondary Execution Paths:** The attacker injected autostart hooks into source repositories. A `SessionStart` entry in `.claude/settings.json` runs `node .claude/setup.mjs`, and a `folderOpen` task in `.vscode/tasks.json` runs `node .vscode/setup.mjs`. This triggers the payload when a cloned repository is merely opened in an IDE or AI agent, without requiring an installation.
4. **Dropper & Runtime:** `setup.mjs` downloads a standalone Bun runtime (v1.3.13) directly from the official release page, extracts it, and uses it to execute the heavily obfuscated payload (`Math_Symbol.js` or `math_init.js`, \~711–728 KB). The dropper then deletes the Bun temporary directory.
5. **Credential Harvesting:** The payload (`collector` component) scans for over 300 unique patterns across developer machines and CI/CD environments. It targets AWS instance metadata, cloud keys (AWS, GCP, Azure, Alibaba), HashiCorp Vault tokens, Kubernetes service-account tokens, GitHub Actions secrets, npm tokens, SSH private keys, and AI tooling credentials (Anthropic, Claude, Codex, Cursor, OpenAI, Gemini).
6. **Exfiltration:** Stolen credentials are gzip-compressed and encrypted with a randomly generated AES-256-GCM key. The AES key is then RSA-encrypted with an attacker's hardcoded public key. Data is exfiltrated via an attacker-controlled HTTPS endpoint, with GitHub repositories serving as a fallback exfiltration channel.
7. **Worm Propagation:** Using stolen npm publishing tokens, the malware enumerates accessible packages, downloads their latest tarballs, inserts the malware and `setup.mjs` loader, adds the `preinstall` hook, increments the patch version, and republishes. Worm-generated commits can be identified by the author name `claude` and the commit message `chore: update config`.
8. **Dead-Man's Switch (Persistence):** The payload writes the stolen GitHub token and an attacker-supplied handler command to `~/.config/gh-token-monitor/`. It persists as a macOS LaunchAgent or a Linux `systemd` user service (enabled with `loginctl enable-linger`) describing itself as a "GitHub Token Validity Monitor." A watcher script polls the GitHub API every 60 seconds. If the token returns an HTTP 4xx (triggered by revocation), it `eval`s the remote-supplied handler string, deletes its own state, and exits. It also self-destructs after a 24-hour TTL.

*Confidence caveat:* Package count figures vary by source (SafeDep verified 353 versions across 79 names; Aikido reported at least 868 packages; Microsoft and Elastic report 400+). The exact total is still moving. The identity of the threat actor remains unconfirmed.

## 4\. Mitigation & containment

### P1 — Within 24 hours: Isolate and preserve (DO NOT REVOKE TOKENS YET)

- **Isolate affected hosts:** Immediately isolate any developer workstation or CI/CD runner that executed the payload or opened an affected repository from the network. Network isolation is safe — without connectivity, the dead-man's switch cannot receive an HTTP 4xx response and will not fire.
- **Do not power off:** Preserve volatile memory for forensic evidence.
- **Identify exposure:** Check lockfiles and `node_modules` for the compromised name/version set (including transitive dependencies like `eslint → file-entry-cache → flat-cache → keyv`). Check for the presence of `.claude/settings.json` and `.vscode/tasks.json` hooks in cloned repositories.

### P2 — Within 72 hours: Host cleanup & Dead-man's switch defusal

- **Extract and preserve handler:** Locate and copy `~/.config/gh-token-monitor/{handler,token,started_at}`, the payload files, and the `plist`/`systemd` unit. Record hashes. **Do not execute the handler; treat it as inert text.** Use the `started_at` file to bound your exposure window.
- **Disable persistence:** Disable `loginctl` linger, remove the `gh-token-monitor` files, and remove the `.claude`/`.vscode` hooks. Clear package caches.
- **Revoke credentials:** Once the dead-man's switch is neutralized on an isolated host, revoke and rotate all credentials exposed during the `started_at` window from a known-clean environment.

### P3 — Within 7 days: Rebuild & Supply Chain Hardening

- **Rebuild systems:** Rebuild CI/CD runners and any host with confirmed execution from trusted images. Arbitrary code ran; the list of known artifacts is not a completeness guarantee.
- **Harden npm configuration:** Disable lifecycle scripts globally where possible (`npm config set ignore-scripts true`) and enforce this in CI/CD pipelines.
- **Audit IDE configurations:** Treat `.claude/`, `.cursor/`, and `.vscode/` directories as part of the execution surface. Implement pre-commit hooks or repository scanning to detect unauthorized `SessionStart` or `folderOpen` tasks.

## 5\. Indicators of compromise

| type            | value                         | confidence | source                |
| --------------- | ----------------------------- | ---------- | --------------------- |
| file\_path      | \~/.config/gh-token-monitor/  | High       | SANS ISC              |
| file\_name      | Math\_Symbol.js               | High       | Elastic Security Labs |
| file\_name      | math\_init.js                 | High       | Elastic Security Labs |
| file\_name      | setup.mjs                     | High       | SANS ISC / Elastic    |
| file\_path      | .claude/settings.json         | High       | SANS ISC / Elastic    |
| file\_path      | .vscode/tasks.json            | High       | SANS ISC / Elastic    |
| service\_name   | GitHub Token Validity Monitor | High       | SANS ISC              |
| commit\_author  | claude                        | High       | Elastic Security Labs |
| commit\_message | chore: update config          | High       | Elastic Security Labs |
| package         | keyv@6.0.0                    | High       | SANS ISC / Socket     |

```iocs
file_path  ~/.config/gh-token-monitor/
file_name  Math_Symbol.js
file_name  math_init.js
file_name  setup.mjs
file_path  .claude/settings.json
file_path  .vscode/tasks.json
service_name  GitHub Token Validity Monitor
commit_author  claude
commit_message  chore: update config
package  keyv@6.0.0

```

## 6\. Detection

```yara
rule CHAINDROP_npm_worm_payload {
    meta:
        author = "Adverse Trace"
        date = "2026-08-05"
        reference = "https://isc.sans.edu/diary/rss/33218"
        description = "Detects CHAINDROP/Shai-Hulud npm worm payload and dropper components"
    strings:
        $preinstall = "\"preinstall\": \"node setup.mjs\"" ascii
        $claude_hook = "SessionStart" ascii
        $vscode_hook = "folderOpen" ascii
        $gh_monitor = "GitHub Token Validity Monitor" ascii
        $dune1 = "shai-hulud" ascii
        $dune2 = "sandworm" ascii
        $dune3 = "fedaykin" ascii
        $dune4 = "tleilaxu" ascii
        $dune5 = "sardaukar" ascii
        $dune6 = "ornithopter" ascii
        $dune7 = "navigator" ascii
        $dune8 = "mentat" ascii
        $dune9 = "ghola" ascii
        $dune10 = "kanly" ascii
        $dune11 = "laza" ascii
        $dune12 = "lasgun" ascii
        $dune13 = "sietch" ascii
    condition:
        $preinstall or $claude_hook or $vscode_hook or $gh_monitor or 5 of ($dune*)
}

```

```yaml
title: Detect CHAINDROP npm Worm Persistence Mechanism
id: 7a9b3c2d-4e5f-6a7b-8c9d-0e1f2a3b4c5d
status: experimental
description: Detects the creation of the gh-token-monitor directory or the systemd/LaunchAgent persistence used by the CHAINDROP npm worm.
author: Adverse Trace
date: 2026/08/05
references:

    - https://isc.sans.edu/diary/rss/33218
logsource:
    product: linux
    service: file_create
detection:
    selection_dir:
        TargetFilename|contains: '.config/gh-token-monitor/'
    selection_service:
        TargetFilename|endswith:

            - '.plist'
            - '.service'
        TargetFilename|contains: 'gh-token-monitor'
    condition: selection_dir or selection_service
falsepositives:

    - Unknown
level: high

```

## 7\. Sources

- SANS Internet Storm Center, "Don't Revoke That Token Yet: Inside the keyv/cacheable npm Worm," https://isc.sans.edu/diary/rss/33218, August 5, 2026.
- Elastic Security Labs, "Shai-Hulud strikes again: CHAINDROP worm hits 400+ npm packages," https://www.elastic.co/security-labs/shai-hulud-chaindrop-npm-supply-chain, August 2026.
- Microsoft Threat Intelligence, "ChainDrop supply chain compromise: Anatomy of a self-propagating worm," https://www.microsoft.com/en-us/security/blog/2026/08/04/chaindrop-supply-chain-compromise-anatomy-self-propagating-worm/, August 4, 2026.
- Snyk Vulnerability Blog, "Inside the keyv npm Compromise: preinstall Malware, Trusted Provenance, and IDE Hooks," https://snyk.io/blog/inside-keyv-npm-compromise-preinstall-malware-trusted-provenance-ide-hooks/, August 2026.
- The Hacker News, "Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks," https://thehackernews.com/2026/08/keyv-linked-npm-worm-poisons-hundreds.html, August 2026.

## 8\. Adverse Trace position

This campaign represents a high-severity supply chain compromise with novel execution and persistence mechanisms that directly threaten EMEA financial services development pipelines. The combination of IDE/AI-agent execution vectors and a dead-man's switch that punishes standard incident response (token revocation) requires a paradigm shift in how teams handle npm compromise triage. The rapid worm propagation and broad credential harvesting scope mean that any organization with a modern JavaScript stack must assume potential exposure. Adverse Trace is actively monitoring the expanding IOC list and will update client detection packages as new package hashes and versions are verified. We strongly advise clients to prioritize host isolation and dead-man's switch defusal before any credential rotation.

---

[Read the original source →](https://isc.sans.edu/diary/rss/33218?ref=f4n6.co.uk)

*Published via PulseTrace — Adverse Trace threat intelligence.*