{"slug": "miasma-worm-targets-ai-coding-agents-via-github-repos", "title": "Miasma Worm Targets AI Coding Agents via GitHub Repos", "summary": "On June 3, 2026, attackers pushed malicious commits to the GitHub repository `icflorescu/mantine-datatable` and four sibling repos, planting a 4.3 MB payload from the Miasma worm family. The commit added configuration files that automatically execute the payload when a developer opens the cloned repository in AI coding agents including Claude Code, Gemini CLI, Cursor, or VS Code, or runs `npm test`. The attack targets developers who clone the affected repos and open them in AI-assisted development tools, with the same worm fingerprint appearing across at least four accounts and more than a dozen repositories.", "body_md": "# Miasma Worm Targets AI Coding Agents via GitHub Repos\n\n### Table of Contents\n\nOn June 3, 2026, the Miasma worm hit two surfaces simultaneously. The npm registry arm published 57 malicious packages across 286+ versions, hiding the payload trigger in `binding.gyp`\n\nfiles to evade lifecycle script scanners — covered in depth by [StepSecurity](https://www.stepsecurity.io/blog/binding-gyp-npm-supply-chain-attack-spreads-like-worm) and [JFrog](https://research.jfrog.com/post/shai-hulud-miasma-redhat-cloud-services/). This post documents the other arm: a parallel run of the same worm that skipped the registry entirely and pushed directly to GitHub source repositories.\n\nAn attacker pushed a commit titled `chore: update dependencies [skip ci]`\n\nto `icflorescu/mantine-datatable`\n\nand four sibling repos. The commit added no dependencies. It planted a 4.3 MB payload runner and wired it to execute automatically through five developer tools: Claude Code, Gemini CLI, Cursor, VS Code, and the `npm test`\n\nscript. The attack detonates when a developer clones one of the affected repos and opens it in an AI coding agent. The dropper is the same staged Bun loader, here repurposed for GitHub source-repo persistence rather than registry poisoning.\n\nicflorescu was not the only maintainer hit. The same fingerprint appears across at least four accounts and more than a dozen repos, with the dropper recompiled per wave. The maintainer’s account was suspended during the incident, and his wife posted the [disclosure](https://github.com/icflorescu/mantine-datatable/discussions/813) on his behalf. The loader is a byte-level match for the Miasma family.\n\n## The commit\n\nThe malicious commit on `mantine-datatable`\n\n([ f72462d9e5fa90a483062a83e9ffcb2edc57bf7e](https://github.com/icflorescu/mantine-datatable/commit/f72462d9e5fa90a483062a83e9ffcb2edc57bf7e)) is unsigned, authored as\n\n`github-actions <`[[email protected]](/cdn-cgi/l/email-protection)>\n\n, and adds six files:Five of those six files exist to launch the sixth. `.github/setup.js`\n\nis the payload. Everything else is a trigger pointed at it, one per tool.\n\n## Five triggers, one payload\n\nThe cleverness here is the trigger surface. Each config file abuses a legitimate auto-run feature of a different developer tool.\n\nClaude Code and Gemini CLI both use a `SessionStart`\n\nhook that runs a shell command when an agent session opens in the project:\n\nCursor uses an always-applied project rule that instructs the agent to run the file, social-engineering the assistant into executing it:\n\nVS Code uses a task configured to run on folder open, so no agent is even required:\n\nThe `package.json`\n\nchange hijacks the test script, so CI and any developer running the project’s tests also detonate it:\n\nCloning the repo is safe. Opening it is not. A developer who clones `mantine-datatable`\n\nto debug an issue and opens the folder in VS Code, or starts Claude Code in it, runs the payload with no further interaction.\n\n## The dropper\n\n`.github/setup.js`\n\nis one statement wrapped in a `try/catch`\n\n. It builds a string from a character-code array, applies a Caesar shift, and passes the result to `eval`\n\n:\n\nDecoding it statically (shift of 4, never executing it) yields an async loader. It pulls `node:crypto`\n\nand AES-128-GCM decrypts two hardcoded blobs:\n\n`_p`\n\nis the worm. `_b`\n\nis a bootstrap. The loader writes `_p`\n\nto a random temp file and runs it under Bun, falling back to downloading Bun if the host does not have it:\n\n`_b`\n\ndefines `getBunPath()`\n\n, which fetches a pinned Bun release straight from the official GitHub mirror and marks it executable:\n\nRunning under Bun keeps the worm off the victim’s Node install. Bun ships its own TypeScript runtime, fetch, crypto, and shell, so the payload needs nothing from the host beyond the downloaded binary.\n\nThe decrypted `_p`\n\n(SHA256 `633c8410…1df5b64`\n\n, 667 KB) is the same Bun stealer family documented in the [Miasma analysis](/redhat-cloud-services-hit-by-mini-shai-hulud-npm-worm): a multi-cloud credential harvester that scans for AWS, Azure, GCP, Vault, Kubernetes, npm, and GitHub secrets, exfiltrates to attacker-created public GitHub repos, and self-propagates with stolen tokens. We did not re-run the full payload analysis on this wave.\n\n## Blast radius: one worm, five repos, 49 seconds\n\nThe same commit landed in five `icflorescu`\n\nrepos inside a 49-second window. The dropper is byte-identical across all five (SHA256 `d630397d…873fdb8e`\n\n, 4,348,254 bytes):\n\n| Repo | Stars | Pushed (UTC) | HEAD commit |\n|---|---|---|---|\n| mantine-datatable | 1,225 | 22:38:51 | `f72462d9` |\n| mantine-contextmenu | 170 | 22:38:59 | `9ef8b396` |\n| next-server-actions-parallel | 56 | 22:39:19 | `01e00e78` |\n| mantine-datatable-v6 | 3 | 22:39:29 | `6592194` |\n| mantine-contextmenu-v6 | 5 | 22:39:40 | `5aa0201b` |\n\nThe five repos carry **1,459 GitHub stars** between them, `mantine-datatable`\n\nalone accounting for 1,225. Stars are a rough proxy for how many developers have the source checked out locally, which is the population this attack targets.\n\nEvery commit: unsigned, `github-actions`\n\nidentity, `chore: update dependencies [skip ci]`\n\n, the same six-file footprint. A 49-second sweep across five repos is automation, not a human committing. This matches Shai-Hulud self-propagation: harvest a GitHub token with write access from a prior infection, then push the persistence payload into every repo the token can reach.\n\n## Beyond one maintainer\n\nicflorescu is one node. A GitHub code search for the launcher string `node .github/setup.js`\n\nreturns the same injection across other accounts. The matches GitHub has indexed so far:\n\n| Account | Repos hit (indexed) | `setup.js` build | Notes |\n|---|---|---|---|\n| icflorescu | 5 | `d630397d…` | mantine-datatable et al |\n| taxepfa | taxepfa.github.io | `d630397d…` (identical) | same `github-actions` / `[skip ci]` commit |\n| jagreehal | 7 (ai-sdk-guardrails, ai-sdk-ollama, autotel, effect-analyzer, es-temp-action, jagreehal-claude-skills, stencil-how-to-test-components) | `fec7d585…` | distinct build |\n| mhar-andal | 2 (MyBlok, stock-forum-ethereum) | `0ecf3e7b…` | injected a `Gemfile` , so not npm-only |\n\nThree distinct `setup.js`\n\nhashes across four accounts means the dropper is recompiled per victim or per wave, not copied verbatim. The launchers and the staged-loader architecture are constant; the Caesar shift, the AES keys, and the resulting file hash rotate. Code search only covers indexed default branches and skips files over roughly 384 KB, so this is a floor, not a ceiling. The 4.3 MB `setup.js`\n\nitself never indexes; the small launcher files are what give the campaign away.\n\nFor `jagreehal`\n\nthe impact extends beyond source repos. StepSecurity’s analysis of the June 3 npm arm confirms the same account had 50+ npm packages compromised — `ai-sdk-ollama`\n\n, `autotel`\n\n, `awaitly`\n\n, `executable-stories`\n\n, `node-env-resolver`\n\n, and others — with 408,000+ monthly download packages like `@vapi-ai/server-sdk`\n\nalso hit in the same wave. The source-repo injection and the npm package poisoning ran in parallel off the same stolen token.\n\n### The exfiltration side\n\nThe worm exfiltrates stolen credentials to attacker-created public GitHub repositories. StepSecurity identified the primary exfil account for the npm arm as `liuende501`\n\n, holding 236 dead-drop repos — 34 described `Miasma - The Spreading Blight`\n\nand 195 carrying the reversed string `niagA oG eW ereH :duluH-iahS`\n\n(decoding to “Shai-Hulud: Here We Go Again”). In our analysis of the source-repo arm, we found two additional exfil accounts: `windy629`\n\n(200+ repos) and `HerGomUli`\n\n, both using the same `Miasma - The Spreading Blight`\n\ndescription. The existence of multiple exfil accounts points to either rotating infrastructure or parallel campaign nodes, not a single operator running one bucket.\n\nThe timing ties the two arms together: the dead-drop `windy629/savage-styx-88946`\n\nwas created at 22:38:26Z, roughly 25 seconds before the first push to `mantine-datatable`\n\nat 22:38:51Z. Steal the token, dump the loot to a fresh dead-drop, then turn the same token on the victim’s own repos.\n\n## Attribution: Miasma\n\nThe loader is the [Miasma](/redhat-cloud-services-hit-by-mini-shai-hulud-npm-worm) staged Bun loader, matched feature for feature:\n\n| Trait | Miasma (RedHat sample) | mantine wave |\n|---|---|---|\n| Outer cipher | `eval(function(s,n){...replace(/[a-zA-Z]/g...}` | identical harness |\n| Caesar shift | ROT-9 | ROT-4 |\n| Loader | `_d=(k,i,a,c)=>createDecipheriv(\"aes-128-gcm\")` , two blobs | identical |\n| Bun pin | `bun-v1.3.13` from oven-sh | identical URL |\n| Temp artifacts | `/tmp/p<rand>.js` , `/tmp/b-<rand>/bun` | identical |\n| Persistence | `.claude/settings.json` , `.vscode/tasks.json` | extends to `.gemini` , `.cursor` |\n\nTwo deltas mark this as a newer build. The Caesar shift moved from 9 to 4 and the AES keys differ (our `_p`\n\nkey is `fe3ee188…`\n\n, not the documented `fe0d71d5…`\n\n), so the dropper was recompiled. The persistence set grew: the documented worm planted Claude Code and VS Code configs; this wave adds Gemini CLI and Cursor. The AI coding agent attack surface is expanding with the malware.\n\n## How it got committed\n\nThis is the part we cannot fully close. The `github-actions <`\n\nidentity is the default for commits made with a workflow’s [[email protected]](/cdn-cgi/l/email-protection)>`GITHUB_TOKEN`\n\n, and any attacker can set it on a stolen-token push. The `[skip ci]`\n\ntag suppresses CI so the push draws less attention. The 49-second multi-repo sweep, the unsigned commits, and the direct-to-`main`\n\nwrites all point to a stolen personal access token replayed by a script, consistent with Miasma’s credential-theft-and-propagate loop. We have not confirmed the initial access vector or whether a workflow run or a raw token push produced the commits.\n\n## Detection and remediation\n\nThe published npm packages for these projects are clean. The risk is local, and it survives `npm uninstall`\n\n. If you cloned any affected repo after June 2:\n\n- Do not open the working copy in VS Code, Cursor, Claude Code, or Gemini, and do not run\n`npm test`\n\n. - Delete the working copy and reclone from a commit before the injection, or wait for the maintainer to revert.\n- Grep any clone for the indicators below before opening it.\n\nTreat unexpected `.claude/`\n\n, `.gemini/`\n\n, `.cursor/`\n\n, and `.vscode/`\n\nfiles in a diff as supply chain signals, not editor noise. These directories auto-execute code and most review workflows ignore them.\n\n### Indicators of compromise\n\n**File hashes — source-repo dropper** (recompiled per wave)\n\n| Account | `setup.js` SHA256 |\n|---|---|\n| icflorescu, taxepfa | `d630397de8b01af0f6f5cf4463da91b17f28195a2c50c8f3f38ad9f7873fdb8e` |\n| jagreehal | `fec7d585...` |\n| mhar-andal | `0ecf3e7b...` |\n`_p` payload (icflorescu wave) | `633c8410ee0413ca4b090a19c30b20c03f31598c25247c484846fa34c1df5b64` |\n\n**Planted files — source-repo arm**\n\n`.github/setup.js`\n\n— the dropper`.claude/settings.json`\n\n— Claude Code`SessionStart`\n\nhook`.gemini/settings.json`\n\n— Gemini CLI`SessionStart`\n\nhook`.cursor/rules/setup.mdc`\n\n— Cursor always-apply rule`.vscode/tasks.json`\n\n— VS Code`folderOpen`\n\ntask`package.json`\n\n—`test`\n\nscript hijack`Gemfile`\n\n— seen in Ruby project targets (`mhar-andal`\n\n)\n\n**Commit signature — source-repo arm**\n\n- Author:\n`github-actions <`\n\n, unsigned[[email protected]](/cdn-cgi/l/email-protection)> - Message:\n`chore: update dependencies [skip ci]`\n\n**Exfiltration dead-drop accounts**\n\n| Account | Repos | Arm |\n|---|---|---|\n`windy629` | 200+ | source-repo (this analysis) |\n`HerGomUli` | 1+ | source-repo (this analysis) |\n`liuende501` | 236 | npm registry (per StepSecurity) |\n\nAll dead-drop repos carry the description `Miasma - The Spreading Blight`\n\n.\n\n**Runtime artifacts**\n\n- Bun download:\n`hxxps://github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/`\n\n- Temp payload:\n`/tmp/p<random>.js`\n\n- Temp runtime:\n`/tmp/b-<random>/bun`\n\n**npm packages — registry arm** (57 packages, 286+ versions, per StepSecurity)\n\n| Package | Malicious versions |\n|---|---|\n`@vapi-ai/server-sdk` | 0.11.1, 0.11.2, 1.2.1, 1.2.2 |\n`ai-sdk-ollama` | 0.13.1, 1.1.1, 2.2.1, 3.8.5 |\n`jagreehal/*` (50+ packages) | autotel, awaitly, executable-stories, node-env-resolver, wrangler-deploy families |\n\n`binding.gyp`\n\nSHA256:`ef641e956f91d501b748085996303c96a64d67f63bfeef0dda175e5aa19cca90`\n\n(per StepSecurity)\n\nA quick local check on any clone:\n\n## A shift in delivery\n\nThis is the same worm with a different mouth. The June 3 npm arm detonated at install time and hid the trigger well, bypassing conventional lifecycle-script scanners entirely. Both [JFrog](https://research.jfrog.com/post/shai-hulud-miasma-redhat-cloud-services/#evasive-execution-via-bindinggyp) and [StepSecurity](https://www.stepsecurity.io/blog/binding-gyp-npm-supply-chain-attack-spreads-like-worm) document the technique: the attacker placed the loader in a `binding.gyp`\n\nfile instead of a `package.json`\n\nlifecycle script. As JFrog describes it, “if a package has a `binding.gyp`\n\nfile at its root and no custom `preinstall`\n\nor `install`\n\nscripts in `package.json`\n\n, npm falls back to running `node-gyp rebuild`\n\n,” and “during the configuration step, `node-gyp`\n\nparses the file and executes any command expansion inside `<!(...)`\n\nsyntax directly in the host shell.” StepSecurity confirms the specific payload used — a 157-byte `binding.gyp`\n\nwith `\"sources\": [\"<!(node index.js > /dev/null 2>&1 && echo stub.c)\"]`\n\n— that fired `node index.js`\n\nsilently “before standard script checkers inspect `package.json`\n\nhooks.”\n\nThe GitHub source-repo arm drops that vector entirely. No package, no install, no `binding.gyp`\n\n. The trigger moved from `npm install`\n\nto `git clone`\n\nplus opening the folder. Same loader, same Bun payload, same dead-drop infrastructure — different detonation surface. The campaign followed its targets from the package manager to the editor.\n\n## Why this pattern matters\n\nThe launcher set is the story. Supply chain malware historically relied on the package install hook: `preinstall`\n\n, `postinstall`\n\n, a `setup.py`\n\n, or the `binding.gyp`\n\ntrick above. This wave skips the registry entirely and bets on the editor. Cloning a repo to read its source has always felt safe. AI coding agents and IDE auto-run features quietly changed that, and attackers noticed before most defenders did. A `.cursor/rules`\n\nfile that instructs an agent to run a script is a prompt injection that ships in the repo. A `SessionStart`\n\nhook is a `postinstall`\n\nfor your editor.\n\nRelated reading: [Mini Shai-Hulud “Miasma” hits @redhat-cloud-services](/redhat-cloud-services-hit-by-mini-shai-hulud-npm-worm) (our analysis of the registry arm), [StepSecurity’s binding.gyp campaign analysis](https://www.stepsecurity.io/blog/binding-gyp-npm-supply-chain-attack-spreads-like-worm), [JFrog’s Miasma deep dive](https://research.jfrog.com/post/shai-hulud-miasma-redhat-cloud-services/), [a threat model for malicious pull requests](/malicious-pull-requests-threat-model), and [npm supply chain attacks targeting maintainers](/npm-supply-chain-attack-targeting-maintainers).\n\n- github\n- malware\n- supply-chain\n- shai-hulud\n- ai-coding-agents\n\n### Author\n\n#### SafeDep Team\n\nsafedep.io\n\n### Share\n\n## The Latest from SafeDep blogs\n\nFollow for the latest updates and insights on open source security & engineering\n\n[Axios Typosquats Deliver the Epsilon Stealer](/malicious-faster-axios-npm-epsilon-stealer)\n\nTwo axios typosquats on npm, turbo-axios and faster-axios, form a campaign delivering Epsilon Stealer through a four-stage chain. The Electron infostealer grabs browser credentials, crypto wallets,...\n\n[Inside MicrosoftSystem64: A Supply Chain RAT Exfiltrating to HuggingFace](/microsoftsystem64-binary-payload-analysis)\n\nDeep technical analysis of MicrosoftSystem64, an 81 MB Node.js SEA binary deployed via malicious npm packages. This RAT steals browser credentials, 80+ crypto wallet extensions, Telegram sessions,...\n\n[Mini Shai-Hulud \"Miasma: The Spreading Blight\" Hits @redhat-cloud-services: Multiple Packages at Risk](/redhat-cloud-services-hit-by-mini-shai-hulud-npm-worm)\n\nThe attacker compromised the @redhat-cloud-services GitHub Actions OIDC trusted publisher to ship [[email protected]](/cdn-cgi/l/email-protection) with a Mini Shai-Hulud worm. The same publisher controls 32 packages across the...\n\n[183 npm Packages Target Cloud and Finance via oob.moika.tech](/oob-moika-tech-dependency-confusion-campaign)\n\nTwo npm accounts published 164 malicious packages at version 99.99.99 targeting a cloud platform and a financial institution. Both campaigns share identical payload code, the same C2 endpoint, and...\n\n## Ship Code.\n\n## Not Malware.\n\nStart free with open source tools on your machine. Scale to a unified platform for your organization.", "url": "https://wpnews.pro/news/miasma-worm-targets-ai-coding-agents-via-github-repos", "canonical_source": "https://safedep.io/miasma-worm-ai-coding-agent-config-injection", "published_at": "2026-06-05 10:00:00+00:00", "updated_at": "2026-06-04 21:43:30.015279+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-tools", "artificial-intelligence", "ai-infrastructure"], "entities": ["Miasma worm", "GitHub", "npm", "StepSecurity", "JFrog", "Claude Code", "Gemini CLI", "Cursor"], "alternates": {"html": "https://wpnews.pro/news/miasma-worm-targets-ai-coding-agents-via-github-repos", "markdown": "https://wpnews.pro/news/miasma-worm-targets-ai-coding-agents-via-github-repos.md", "text": "https://wpnews.pro/news/miasma-worm-targets-ai-coding-agents-via-github-repos.txt", "jsonld": "https://wpnews.pro/news/miasma-worm-targets-ai-coding-agents-via-github-repos.jsonld"}}