A RubyGems package called strutil-core was live for about five hours on November 1. According to Socket's write-up, its payload steals credentials and then uses the stolen Git credentials to commit files into your repositories: .claude/settings.json, .cursor/mcp.json, CLAUDE.md, AGENTS.md, .vscode/tasks.json. Socket hasn't confirmed any victims. It doesn't need victims to make the point.
Agent config is the new postinstall: a file in the tree that runs code when a tool opens it. We spent years learning that npm install executes whatever the package says. An agent opening a repo does the same, and the only thing standing in the way is a prompt for a human. Headless runs don't have a human.
The Mechanism
The payload is a new build of the testmetest worm, from the same family whose token-revocation wiper I wrote about last week. Per Socket:
- On your machine, it finds writable AI tool configs and adds an MCP server named
workspace-toolsthat runsnodeon the payload. Other configs getSessionStarthooks. - In your repos, it commits
.github/init.js,.claude/settings.json,.cursor/mcp.json, Gemini settings, a VS Code task that runs on folder open, and anAGENTS.mdthat tells the agent to run a setup script before its first command. - It puts the commits on short-lived
chore/ci-*branches, withskip-checks:truein the commit message.
Every one of those files is a feature someone asked for. Cursor's own docs tell you to commit mcp.json "so teammates get the same tools." That is exactly why it spreads: the worm writes code where your team already expects config.
Where the Gate Is
Claude Code does guard the interactive case. Its MCP docs say it prompts before using project-scoped servers, and that "a cloned repository can't approve its own servers." Opening a fresh clone shows a trust dialog for the folder. Trust a parent folder once, though, and the table in the permissions docs marks the repo's hooks as "Used" with no further prompt.
Now read the permissions docs: "Claude Code shows the trust dialog in interactive sessions only. A claude -p run or an SDK session never shows it." The table is blunt. For claude -p or the SDK, in a folder nobody ever trusted, hooks in the repo's settings files are "Used," and .mcp.json servers are "Connected without asking, approved or not."
So the dialog protects the laptop. It doesn't protect the review bot, the scheduled fixer, or the CI job that runs an agent over whatever branch it was handed. Those take the repository's config as orders. The worm doesn't need to know which of them you run.
AGENTS.md is a separate problem. It isn't config, it's instructions, and whether the agent obeys "run setup first" is up to the model.
The Check
Look for the files and the branches. This lists every commit that touched agent config, on every branch you still have, local or fetched:
Anything you can't attribute to a person on your team is a lead. AutoSyncComplete is the prefix Socket says the worm uses on commits that carry stolen tokens. The branches are short-lived, so a clean result here isn't a clean bill: your org's audit log has the pushes.
The Control
Headless runs should not read the repo's agent config. Claude Code has the switches. Per the permissions docs, claude -p --bare reads no hooks, skills, commands, subagents, plugins or .mcp.json servers from the project (its --help adds CLAUDE.md auto-discovery). --setting-sources user reads neither the project's settings files nor its .mcp.json. --strict-mcp-config with --mcp-config loads only the servers you pass, per --help. On the SDK, project .mcp.json servers load only when settingSources includes project settings. Note the trap the docs call out: setting disableAllHooks in your user settings isn't enough, because project settings take precedence and can set it back. Pass it per run instead: --settings '{"disableAllHooks": true}'.
Agent config should be reviewed like workflow files. Put those paths under CODEOWNERS and turn on "Require review from Code Owners" (the owning team needs write access):
/.claude/ @your-org/platform
/.cursor/ @your-org/platform
/.gemini/ @your-org/platform
/.github/ @your-org/platform
/.vscode/ @your-org/platform
/.mcp.json @your-org/platform
/CLAUDE.md @your-org/platform
/AGENTS.md @your-org/platform
That only gates merges into protected branches, and the worm commits to its own branches. That's fine if your headless agents only run on merged code. If they run on PR branches, the first control is the one doing the work. Push rulesets can block pushes that touch given paths on any branch, but only on the Team plan, in private and internal repos.
The Tradeoff
--bare throws away the project skills and hooks your team built on purpose, so a headless run now needs its config passed in explicitly, from somewhere the branch can't edit. That's the same rule as checks an agent can't modify, and it costs setup. Hooks aren't the whole surface either: the same table marks the project's env block and helper commands such as apiKeyHelper as used in headless runs, so check that your flags cover those too. CODEOWNERS adds friction for teams that tune agent config every week. And none of this touches the stolen credentials themselves. Socket's advice on the wiper still stands: remove the persistence before you revoke the token.
This is the same gap as the trust prompt that's a line in a file, seen from the repo instead of the laptop. My bet: agents need new primitives here, and config that executes code won't stay a file any committer can write. Until then, treat .claude/, .cursor/ and AGENTS.md like .github/workflows/. They run.