AISecOps supply chain 02
Your Agent Config Is Executable Code
ChainDrop used npm lifecycle scripts to steal credentials and spread, then planted Claude Code and VS Code configuration as secondary execution paths. Those files belong in the executable supply-chain surface.
Part 6 Detection Contracts
We have spent years teaching developers that the dangerous moment is npm install.
ChainDrop kept that trigger, then added another one. After stealing GitHub credentials, the worm could plant files under .claude/ and .vscode/ so later agent or editor activity could restart the payload. The package was the initial delivery path. The repository became a persistence path.
That changes how I think about agent configuration. A file such as .claude/settings.json may look like project metadata. A .vscode/tasks.json file may look like editor setup. If either can cause a process to start, fetch code, or grant a tool permission, it belongs in the executable supply-chain surface.
It should be reviewed like a build script, CI workflow, Git hook, or container entrypoint.
What Microsoft confirmed
Microsoft Threat Intelligence reported on August 4 that ChainDrop affected more than 400 npm packages across unrelated publishers. The compromised packages included a large, obfuscated JavaScript payload and a preinstall script that launched setup.mjs before package installation completed.
Once running, the malware searched developer workstations and CI environments for credentials. Microsoft documented collection and use involving npm, GitHub, AWS, Kubernetes, and HashiCorp Vault. The worm could use recovered npm publishing authority to download other packages, insert itself, increment the patch version, and publish the result.
That is the self-propagating part. One compromised maintainer identity could turn into malicious releases across every package it was allowed to publish.
The malware also used stolen GitHub access to add files to eligible repository branches:
.claude/settings.json.claude/setup.mjs.vscode/tasks.json.vscode/setup.mjs
Microsoft describes these files as a secondary infection route. Future Claude Code or VS Code activity could restart the payload after the original package installation had finished.
The wording matters. This was not simply a case where cloning any affected repository automatically executed code. The confirmed initial path was the npm lifecycle hook. The planted configuration then created another chance to execute inside repositories the attacker could modify.
That is still a serious boundary failure. The files developers use to describe their local tools became part of the malware’s persistence design.
A repository can contain startup behavior
A repository is usually treated as data until someone builds or runs it. Modern development tools have made that distinction less reliable.
A project can contain instructions for:
- dependency installation;
- editor tasks;
- development containers;
- CI workflows;
- Git hooks and hook managers;
- language-server startup;
- debugging and test launchers;
- agent hooks, tools, permissions, and session behavior.
Some of those instructions are inert until a person explicitly invokes them. Others can run when a folder is trusted, a session starts, a dependency is installed, or a workflow begins.
VS Code documents a runOn: "folderOpen" option for tasks. Automatic tasks are disabled by default and do not run in an untrusted workspace, which is an important safeguard. A user can still allow them for a trusted workspace. If malicious configuration reaches a repository that the developer already trusts, that saved trust decision becomes part of the attack path.
Agent runtimes add another startup surface. Hooks are useful because they let teams load context, run checks, format files, or connect an agent to an existing workflow. The security property is the same as every other hook system: a configuration file can name code that runs with the developer’s local authority.
Calling the file JSON does not make the effect declarative.
ChainDrop crossed three supply chains
The incident is easier to understand when split into three connected supply chains.
The package supply chain
The malicious preinstall script executed before normal application testing could inspect the installed result. The worm then reused stolen npm authority to create additional releases.
The important evidence is not only the package name and version. Microsoft found malicious releases without matching source commits, pull requests, tags, or legitimate release activity. The published tarball and the public repository had diverged.
That gives defenders a durable control: compare what was published with what the approved source and build pipeline produced.
The identity supply chain
The worm did not need to compromise every project independently. It looked for identities that already had authority across several systems.
An npm token could publish more packages. A GitHub token could modify repositories and workflows. CI credentials could expose secrets and publishing paths. Cloud, Kubernetes, and Vault access could expand the impact beyond source code.
This is why a software-supply-chain incident is also an identity incident. Deleting the malicious dependency does not invalidate the credentials it already collected or undo the releases and repository changes made with them.
The developer-tool supply chain
The planted Claude Code and VS Code files created a path from compromised repository access back to a developer workstation or agent session.
That path is easy to miss because configuration files are often excluded from the threat model. Teams review application code and dependencies while treating .claude/, .vscode/, and similar directories as convenience settings.
ChainDrop demonstrated that an attacker can chain all three surfaces:
malicious package
-> developer or CI credential theft
-> package and repository modification
-> agent or editor startup configuration
-> another execution opportunity
Each arrow crosses a different authority boundary. Each needs its own evidence and containment step.
The command server did not have to stay in one place
Microsoft found that ChainDrop could retrieve its active command-and-control destination through an Ethereum smart contract. The malware queried contract 0xE1f2395ee43e45A1556EC6438a88c31B83493103. It also had a signed GitHub commit as a fallback discovery mechanism and could use public GitHub repositories as a fallback exfiltration path.
The design separates the malware from the current server address. An operator can update the on-chain value without publishing a new malware version. Blocking yesterday’s domain does not remove the resolution mechanism.
This does not make the infrastructure undetectable. It changes the useful signals.
A development workstation, build runner, or agent sandbox that has never needed Ethereum JSON-RPC should not quietly begin querying a contract during package installation. A Bun or Node process resolving a contract, downloading another runtime, or contacting a new dynamic domain is valuable context even if the final address changes.
The detection should focus on the sequence and workload identity, not only the current domain.
A detection contract for repository-triggered execution
The minimum detection question is straightforward:
What caused this process to run, and which reviewed artifact authorized it?
Answering it requires evidence across the install, repository, editor, agent, identity, and publishing planes.
| Signal | Useful join |
|---|---|
node setup.mjs during dependency installation |
Package name, version, parent installer, lockfile, and tarball hash |
| Node downloading or launching Bun | Initiating package script, destination, downloaded file, and child process |
New .claude/ or .vscode/ executable configuration |
Commit author, token identity, branch, review status, and later process start |
folderOpen or session-start hook |
Workspace trust state, configuration commit, command, and network activity |
| New npm patch release | Publisher identity, source commit, tag, build workflow, and provenance |
| Package modification across several projects | Shared publisher identity and release timing |
| Ethereum RPC or signed-commit lookup | Initiating process, package install, contract or repository, and returned destination |
| Credential validation against cloud or developer services | Process ancestry, source host, token owner, and subsequent resource access |
Any one event may have a legitimate explanation. The joined sequence is much harder to dismiss.
For example, downloading Bun is not malicious. Downloading it from a preinstall loader in a newly released transitive dependency, then reading environment variables and modifying .claude/settings.json, is a high-confidence chain.
The same principle applies to agent observability. Logging that an agent session started is not enough. Record which project configuration was loaded, its source revision and digest, which hooks it registered, which commands actually ran, and which identity approved or inherited the workspace trust decision.
Review configuration as code that can run
The repository review policy should identify files that create execution, not depend on a short list of filenames.
At minimum, I would require review for changes to:
- npm lifecycle scripts and package-manager configuration;
.claude/,.vscode/, and other agent or editor directories;- CI and release workflows;
- development-container definitions;
- Git hooks and hook-manager configuration;
- test, task, debug, and bootstrap scripts;
- commands that download runtimes or execute remote content;
- permissions that let an agent invoke shell, deployment, secret, or cloud tools.
Repository protections should assign owners to these paths. Automated review can flag new startup hooks, network fetches, encoded payloads, runtime bootstrapping, and commands that read credentials or environment variables.
The review also needs the generated artifact. ChainDrop’s package propagation could publish modified tarballs without matching source changes. A clean Git diff does not prove that the registry artifact is clean.
Release verification should connect:
approved commit -> protected workflow -> short-lived publishing identity -> package digest -> provenance record
npm trusted publishing removes reusable publishing tokens from supported CI workflows and produces provenance attestations. It does not make a compromised workflow safe, but it narrows the identity path and makes the expected publication source explicit.
Make the first interaction boring
The safest time to inspect a repository is before it receives ordinary developer authority.
A guarded onboarding flow can be simple:
- Clone or fetch into a disposable environment without personal, cloud, package, or production credentials.
- Keep the workspace untrusted and automatic editor tasks disabled.
- Inspect lifecycle scripts, agent hooks, editor tasks, workflows, and bootstrap files before installation.
- Compare the lockfile and package contents with an approved dependency source.
- Install with lifecycle scripts blocked, then explicitly approve the small set that actually needs them.
- Observe network and process behavior during the first build and test.
- Grant only the project-specific credentials needed for normal work.
Current npm tooling supports stronger script controls than a blanket allow or deny. npm documents an allowScripts policy that blocks dependency install scripts unless they are explicitly approved. Approvals can be pinned to a package version. The older ignore-scripts option remains useful, but it is broader and is not a complete answer for every executable dependency path.
For VS Code, keep automatic tasks off unless a project has a clear reason to use them. Do not mark an unfamiliar repository trusted merely to make warnings disappear. Trust is an execution decision, not a usability preference.
Agent sessions deserve the same staging. The first agent run over an unfamiliar codebase should not inherit shell access, personal GitHub authority, cloud sessions, deployment tools, and secret stores by default.
Incident response does not end at uninstall
Microsoft recommends treating a workstation or build runner that installed an affected package with lifecycle scripts enabled as potentially compromised.
That is the right scope. Removing the package leaves several unanswered questions:
- Which credentials were accessible to the process?
- Which package versions were published with those credentials?
- Which repositories and branches were modified?
- Were agent, editor, CI, or hook configuration files added?
- Which workflows ran after the compromise?
- Which caches, images, and build artifacts contain the malicious files?
- Which cloud, Kubernetes, Vault, or GitHub resources were accessed?
- Did another developer or runner consume a poisoned release or repository state?
Credential rotation should happen from a known-clean system. A token changed from an infected workstation can be stolen again. Rebuild affected developer machines and runners where the evidence cannot establish containment. Purge shared package caches. Rebuild golden images. Verify artifacts produced during the exposure window.
The release pipeline needs its own investigation. Review unexpected patch versions, provenance, tags, workflow runs, OIDC activity, and publisher changes. A clean endpoint does not retract a malicious package that has already reached a registry.
The config file is part of the program
ChainDrop is an npm supply-chain incident, an identity incident, and a developer-tool incident at the same time.
The agent-specific lesson is not that Claude Code or VS Code caused the compromise. The malware reached those surfaces after obtaining repository authority and used features designed for legitimate automation. VS Code’s workspace trust and automatic-task controls are meaningful defenses. Agent hooks are useful when the code and owner are known.
The lesson is that these files create effects. Their paths may begin with a dot and their syntax may be JSON, but their security role is closer to a startup script than a preference file.
Treat them accordingly:
- review them;
- assign owners;
- record their provenance;
- restrict the authority they inherit;
- observe the processes they start;
- test whether one compromised repository can reach another identity or system.
The next supply-chain payload may still arrive through a dependency. The more important question is what other startup paths it can plant once it gets inside.