Securitymalwaregithubnpmclaude-codeai-agents
JFrog Found a Worm in 42 GitHub Repos That Hid 13 MB Payloads From Code Search and Planted Claude Code SessionStart Hooks to Run Them
The testmetest campaign armed real developers' repositories with loaders too big for GitHub's search and contents API, then wired them to the startup hooks of Claude Code, Gemini, Cursor and VS Code.

JFrog’s researchers admit their first pass got it wrong. “Our first GitHub code-search sweep found the execution harness in 26 repositories,” Guy Korolevski and Yair Benamou write, but the .github/init.js files those hooks pointed at “initially appeared empty through the available content paths. That conclusion was wrong.”
Each one held about 13 MB. “GitHub code search did not index the 12.9 to 13.7 MB blobs, and the contents API could not return files of that size.” Walking each repository through the Git trees and blobs APIs instead turned up the real count: “every reachable victim repository was armed.” Ten different-looking wrappers all held the same 4,067,677-character loader and decrypted to the same 2 MB payload; the size differences were an encoding artifact.
The hook is the part anyone using an AI coding tool should read twice. In .claude/settings.json, the attacker added a SessionStart entry that runs node .github/init.js || bun .github/init.js. Claude Code’s documentation says SessionStart “Runs when Claude Code starts a new session or resumes an existing session,” and that a project’s .claude/settings.json can be committed to the repo. “Equivalent triggers were planted for Gemini, Cursor MCP configuration and VS Code folder-open tasks,” JFrog writes. The loader launches detached with its output ignored, so the session opens normally.
The victims were real people. One account dates to 2013 and belongs to an Argentine PHP and Laravel developer. “On September 28 the attacker renamed repositories en masse with the prefix come-to-telegram-rickluminari1– and armed 13 of them in a two-minute batch.” Forged commits copied old messages and author dates from each repo’s real history, and appended skip-checks:true so CI wouldn’t run on them.
SafeDep documented the npm side first, on October 22. “An operator is testing a Miasma-family npm worm in public,” Kunal Singh writes; 19 packages from the same operator landed between October 19 and 27. It steals “AI tool credentials for Claude, Codex, Gemini and Copilot,” plus SSH keys, registry tokens, .env files and browser logins, and “npm install –ignore-scripts does not stop it.” It also installs “a wiper that deletes the home directory when the victim revokes the stolen GitHub token,” which is why JFrog says to remove its persistence before you revoke anything.
SafeDep had found no third-party victims when it published. JFrog’s answer is that nobody could have, by looking the usual way. “The payload blobs were large enough to evade the GitHub search and API paths normally used to find this kind of compromise.” How many more repos are armed past the ones JFrog could reach, neither firm says.
Agent config folders are becoming what autorun.inf was on a CD: a file nobody looks at that runs first. Every tool that reads project-level settings at startup inherits the problem, and the fix will look the same everywhere, a trust prompt that can’t be skipped by automation without someone saying so on purpose.
Expect scanners to start walking Git trees directly, and expect attackers to find the next size limit or API gap the scanners don’t know they have.