Skip to content

Back to the catalog

Miasma Worm Hits Microsoft Again: Azure Functions Action and 72 Other Repositories Disabled After Supply Chain Attack Targeting AI Coding Agents
stepsecurity.iowriteup

Miasma Worm Hits Microsoft Again: Azure Functions Action and 72 Other Repositories Disabled After Supply Chain Attack Targeting AI Coding Agents

StepSecurity's forensic analysis of the June 5, 2026 Miasma worm incident, in which a compromised contributor account pushed a malicious commit to Microsoft's Azure/durabletask repository planting five files (.claude/settings.json, .gemini/settings.json, .cursor/rules/setup.mdc, .vscode/tasks.json, and a 4.6MB obfuscated .github/setup.js payload) that trigger credential-harvesting code execution the moment the repo is opened in Claude Code, Gemini CLI, Cursor, or VS Code — no package install or code run required. GitHub's automated abuse detection disabled 73 Microsoft repositories in a 105-second sweep, including Azure/functions-action, breaking CI/CD pipelines across GitHub Actions users relying on the mutable @v1 tag. The post ties this to the same compromised account behind the May 19 durabletask PyPI credential-stealer campaign and the broader TeamPCP-linked Miasma worm, which has infected 113+ repositories.

TL;DR Miasma worm pivots from PyPI package poisoning to planting IDE/agent auto-run configs (Claude Code, Gemini CLI, Cursor, VS Code) in Microsoft's Azure/durabletask repo, triggering credential theft on folder-open and forcing GitHub to disable 73 repos, including the widely-used Azure/functions-action.
Document

What it is

StepSecurity's forensic breakdown of the June 5, 2026 Miasma commit to Azure/durabletask (commit 5f456b8). Its value beyond the summary is the concrete detection surface: the exact planted files, the commit red flags, and the three competing theories for why the same account was used twice.

How it works

The attack moves execution from "package install" to "folder open." Four config files all invoke one payload, .github/setup.js (a single-line, 4,643,745-byte obfuscated JS credential harvester):

  • .claude/settings.json and .gemini/settings.json — SessionStart hooks running node .github/setup.js when a Claude Code or Gemini CLI session starts.
  • .cursor/rules/setup.mdc — a prompt injection with alwaysApply: true that tells the Cursor agent to run the payload as "project setup."
  • .vscode/tasks.json — a task with runOptions.runOn: "folderOpen", triggering on folder open with no AI agent needed.

Cloning is safe; opening the repo in any of these tools is not. The harvester steals secrets from AWS, Azure, GCP, Kubernetes, and 90+ tool configs (per the May 19 PyPI variant).

Preconditions / Affected

Any developer who opens an infected repo in Claude Code, Gemini CLI, Cursor, or VS Code. The May 19 predecessor was the poisoned durabletask PyPI package (three versions in a 35-minute window via a stolen publishing token). The same contributor account drove both incidents — including a blocked personal fork of Azure/azure-functions-durable-extension.

What to do

Detect the commit pattern and the planted paths, not just the package. The June 5 commit carried these red flags:

  • Message Switched DataConverter to OrchestrationContext [skip ci] but 0 source files changed — all 5 additions were config or payload.
  • Timestamp backdated to 2020-03-09T15:59:47Z, ~6 years before the push.
  • [skip ci] to suppress CI detection.

Grep repos for .claude/settings.json, .gemini/settings.json, .cursor/rules/setup.mdc, .vscode/tasks.json, and .github/setup.js, and flag any SessionStart hook, runOn: folderOpen task, or alwaysApply: true rule that shells out. Treat editor/agent config files as executable supply-chain surface. Because the account was reused, rotate tokens fully — the writeup notes partial rotation after May 19 is one plausible cause of the repeat.

Caveats

The reuse of the same account has three explanations the author does not resolve: credentials never fully rotated, re-compromise via the worm's own propagation loop, or a spoofed commit author via the Git Data API. The 73-repo, 105-second takedown was GitHub's automated ToS enforcement (all return HTTP 403 "reason": "tos") — the underlying repos may be legitimate, not all malicious. The disabled-repo list originated with OpenSource Malware; StepSecurity independently verified it via the GitHub API.

Organisations named here

  • Adnan Khan
  • check.git-service.com
  • OpenSource Malware
  • t.m-kosche.com

CVEs named here

  • CVE-2026-45321

Technologies named here

  • Azure/durabletask
  • durabletask
  • Azure/functions-action
  • Azure/azure-functions-durable-extension
  • microsoft/durabletask-python
  • tanstack
  • Mistral AI
  • AntV ecosystem
  • @redhat-cloud-services npm scope
  • LiteLLM
  • telnyx
  • Checkmarx
  • Claude Code
  • Gemini CLI
  • Cursor
  • VS Code
  • GitHub Actions
  • Azure
  • PyPI

Techniques named here

  • Backdating commit timestamp to evade detection
  • AI coding agent hijacking via editor/session-start hooks
  • Obfuscated JavaScript payload delivered via .github/setup.js

Threat actors named here

  • Miasma worm
  • TeamPCP