Skip to main content
← All articles
ai

The malware was in .claude/settings.json: when opening a repo becomes code execution

The malware was in .claude/settings.json: when opening a repo becomes code execution

I've gotten comfortable cloning a repo I don't fully trust and opening it in Claude Code to poke around. A worm that hit npm on 4 August 2026 is a pointed reminder that "just opening it" is now a decision with consequences, because the malware did not wait for npm install. It planted itself in the config files my agent and editor read the moment I open the folder.

What happened

The popular keyv package, plus a cluster of siblings under the same maintainer (cacheable, flat-cache, file-entry-cache and others), was compromised. Security firms are tracking this wave as "ChainDrop" (the name StepSecurity gave it), a heavily evolved descendant of the Shai-Hulud worm family. It hit around 09:00 UTC on 4 August and propagated across roughly 444 packages and something like 2,200 poisoned versions (Socket's live tracker was still climbing as I wrote this). Given keyv alone pulls hundreds of millions of downloads a month, the blast radius is enormous.

The part that made me sit up

Most supply-chain malware runs from a preinstall lifecycle script, so npm install is the trigger. This one added a second, nastier path: it plants autostart hooks in the files your tools execute when you open a project, no install required.

  • .claude/settings.json gets a SessionStart hook, run when a Claude Code session begins in that directory.
  • .vscode/tasks.json gets a task with "runOn": "folderOpen", run when you open the folder in VS Code.
  • .claude/setup.mjs and .vscode/setup.mjs are the planted loader payloads those hooks point at.

Read that again as an attacker would. You don't have to install anything. You clone a repo to review it, open it in the editor or point your agent at it, and the hooks fire. The one guardrail is VS Code's Workspace Trust, which gates folderOpen tasks, so opening a checkout is an exposure condition rather than proof code ran. But "I trusted the folder so I could read it" and "I authorized arbitrary code execution" have quietly become the same click.

Opening a repository in an agent-enabled editor is now a code-execution decision. The trust prompt you dismiss to read someone's code is the same prompt that lets their code read you.

The provenance twist

Here's the detail that should bother anyone leaning on supply-chain signing. These poisoned releases shipped with valid npm provenance, cleanly signed by GitHub Actions. Not forged. Genuinely valid. The attacker pushed malicious commits to the source repository first, then let each project's own trusted release workflow build and attest the trojanized code. Provenance did exactly what it promises: it proved which commit was built. It cannot prove that commit was authorized. As Snyk put it, provenance "can faithfully attest a build whose source has already been compromised." Signing attests origin, not integrity, and this is what that distinction costs you in practice.

What I actually did about it

This lands close to home because Claude Code is my daily driver and the payload literally targets its config directory. So, concretely:

  1. Audited my agent and editor config in any repo I'd touched recently: .claude/settings.json for unexpected SessionStart hooks, .vscode/tasks.json for runOn: folderOpen, and any stray setup.mjs / math_init.js loaders. These files are invisible to dependency scanners, so you have to look yourself.
  2. Reinstalled with npm ci --ignore-scripts and pinned the affected packages back to known-clean versions via overrides.
  3. Kept treating "trust this folder" as a real decision. Repos I'm only inspecting now get opened in a throwaway container, the same rule I landed on after the GhostApproval symlink flaw. The agent's approval prompts are not my security boundary; the container is.

And a habit worth adopting generally: a minimum release-age policy, so your tooling doesn't auto-adopt a version published forty minutes ago. This worm did most of its damage in the hours before anyone noticed. A rule as dumb as "don't install versions less than a few days old" would have sat most of us out of the blast radius entirely.

The uncomfortable summary

We spent a decade learning that npm install runs untrusted code. The new lesson is that your AI agent and your editor have their own execution surfaces, defined in dotfiles that ship inside the repositories you clone, and that a validly-signed package can still be malware if the source was poisoned upstream. Point your agent at a stranger's code, and you've invited the stranger's code to point back.

Links

BM
Blue Moose
The moose behind Blue Moose. Full-stack PHP developer — Drupal by day, Symfony by night, tests always.