Tech 10 min read

Microsoft 73-repo Miasma: AI agent startup, not npm install

IkesanContents

TL;DR

Impact On June 5, 2026, GitHub disabled 73 repositories under Azure, Azure-Samples, microsoft, and MicrosoftDocs. The reported starting point is a malicious commit to Azure/durabletask

Trigger Not npm install, but Claude Code and Gemini CLI SessionStart hooks, Cursor always-applied rules, and VS Code folderOpen tasks. .claude/settings.json, .gemini/settings.json, .cursor/rules/setup.mdc, and .vscode/tasks.json are the execution paths

Response A clone or pull of an affected repository is still triageable by itself. For machines that started an AI coding session, loaded Cursor rules, or opened a trusted VS Code workspace with automatic tasks enabled, check .github/setup.js execution, outbound traffic, and exposed GitHub, npm, and cloud credentials


GitHub disabled 73 Microsoft-related public repositories on June 5, 2026.
StepSecurity’s analysis points to a malicious commit in Azure/durabletask as the starting point.
That commit did not change application source code. It added configuration files read by AI coding tools and editors, plus the malicious code body.

This entry point does not go through the package manager.
In the Mini Shai-Hulud @antv wave, the entry point was preinstall or a Git dependency lifecycle script, and Claude Code / VS Code startup paths stayed behind after the hit.
In this Microsoft repository wave, the entry point itself moved to treating the repository as a workspace for an AI agent or VS Code.

Azure/durabletask received startup configuration, not code changes

The commit StepSecurity names is 5f456b8.
The commit message was Switched DataConverter to OrchestrationContext [skip ci], but the changed files did not match that description.
There was no source-code change. The added files were configuration and setup.js.
The commit timestamp is 2020-03-09T15:59:47Z, which does not line up with the actual push timing.
[skip ci], an old timestamp, a misleading message, and configuration-only additions all line up in the same commit.

The confirmed trigger surfaces are Claude Code, Gemini CLI, Cursor, and VS Code.
They are not all the same kind of “auto-run as soon as you open it” behavior.

FileTrigger conditionWhat happens
.claude/settings.jsonClaude Code session startRuns node .github/setup.js through a SessionStart hook
.gemini/settings.jsonGemini CLI session startRuns the same setup.js through Gemini CLI’s hook path
.cursor/rules/setup.mdcCursor reads project rulesUses an alwaysApply: true rule to inject setup execution as an initialization task for the agent
.vscode/tasks.jsonVS Code opens a trusted workspace and automatic tasks are allowedRuns node .github/setup.js through a runOn: "folderOpen" task
.github/setup.jsCalled from the four paths aboveCollects credentials as the malicious code body

Claude Code and Gemini CLI can read session-start hooks from project-local settings files.
Cursor is less a direct shell-execution setting and more an instruction injected into the conversation context through an always-applied rule: run this setup step.
For VS Code, Workspace Trust and automatic task settings are the boundary. Automatic tasks do not run in an untrusted workspace, but .vscode/tasks.json folderOpen tasks can fire in trusted folders or once the workspace has been allowed.

StepSecurity frames cloning alone as safe, while opening the repository is the risky operation.
Here, “opening” does not mean viewing the directory in Finder or running ls. It means handing the directory to an AI coding tool or IDE as a workspace.
Reading .claude/settings.json with cat is a different operation from starting Claude Code inside that directory.

npm ci --ignore-scripts and “wait N days before installing new package versions” do not cover this path.
The tool configuration is read before dependency resolution enters the picture.
The pnpm 11 and Yarn 4.10 age-gate post covers short-lived npm registry exposure, but it does not inspect startup configuration placed directly in a source repository.

73 repositories were disabled in 105 seconds

StepSecurity says it confirmed the 73 disabled repositories through the GitHub API.
The repositories sat under four organizations: Azure, Azure-Samples, microsoft, and MicrosoftDocs. The disable window ran from 2026-06-05 16:00:50 to 16:02:35 UTC, a span of 105 seconds.
That looks more like GitHub-side automated detection than someone disabling repositories one by one by hand.

An article citing OpenSourceMalware’s tally says Azure alone accounted for 49 repositories, including Azure Functions-related projects, language workers, azure-functions-core-tools, and functions-action.
GitHub Actions workflows that referenced a floating tag such as Azure/functions-action@v1 could fail to resolve while the repository was disabled.
That creates a separate impact: legitimate CI can break even before any malware executes.

TechCrunch reported a Microsoft spokesperson saying the company temporarily removed some repositories for investigation, restored some after review, and notified a small number of potentially affected customers.
Public reporting does not show the number of affected people or how many clones had already been taken.

Miasma keeps changing entry points

Read as a standalone event, this is “Microsoft GitHub repositories were disabled.”
Read as part of the Miasma sequence, the entry point is moving.

DateEntry pointWhat changed
2026-05-19Microsoft durabletask PyPI publishing rightsStepSecurity says three malicious versions appeared within 35 minutes. They were pushed directly to PyPI with a compromised publishing token, bypassing CI/CD
Reported 2026-06-02Red Hat @redhat-cloud-services npm scopeMalicious npm packages were published through a legitimate GitHub Actions OIDC path with SLSA provenance. The entry point was preinstall
2026-06-05Azure/durabletask GitHub repositoryThe path moved from a package registry into AI-tool and IDE configuration inside the source repository
Reported 2026-06-07Hades PyPI waveSocket confirmed 37 malicious wheel files across 19 packages. *-setup.pth calls Bun and _index.js at Python startup

The common pattern is that the attacker targets code that runs before the user reads the application code.
In npm, that is preinstall; in Python, it is .pth; in AI agents, it is a session-start hook; in VS Code, it is a workspace task.
For the attacker, these are all places that run before a developer starts normal work.

Same Miasma family, different entry point from the Red Hat npm wave

Microsoft’s June 2 security blog details the Miasma wave in the Red Hat @redhat-cloud-services npm scope.
That wave involved 32 packages and more than 90 malicious versions, published through a legitimate GitHub Actions OIDC path with SLSA provenance.
At install time, preinstall ran a 4.29 MB obfuscated index.js, downloaded Bun, and executed a second-stage malicious body.

Microsoft describes the Red Hat npm payload as collecting GitHub, npm, AWS, Azure, GCP, Vault, Kubernetes, local CLI credentials, SSH keys, browser data, and wallet data.
On CI runners, it pulled secrets from process memory, republished additional packages, and forged SLSA provenance while spreading as a worm.
Microsoft also notes token-monitoring logic and destructive behavior when a decoy token is touched.

The Microsoft 73-repository wave moves the entry point even earlier.
Instead of distributing through the npm registry, it places configuration files into the source repository and uses AI coding tool startup hooks plus rule loading as the entry path.
Even without creating node_modules, opening the repository as a workspace and reaching the relevant tool-configuration load path can put the machine on the execution path.

The Hades PyPI wave follows the same direction.
Socket found 37 malicious wheel files where *-setup.pth is processed at Python startup, downloads Bun, and attempts to run _index.js.
Even without importing the affected package, the .pth file is processed when python, pip, a test runner, a Jupyter kernel, or a CI job starts in that environment.
Across npm, GitHub repositories, and PyPI, Miasma keeps looking for places that run automatically before normal work begins.

Check the workspace, not only dependencies

For a repository that was cloned or pulled and then opened in Claude Code, Gemini CLI, Cursor, or VS Code, check the workspace separately from dependencies.
Start with these files at the workspace root.

.claude/settings.json
.gemini/settings.json
.cursor/rules/setup.mdc
.vscode/tasks.json
.github/setup.js

For Cursor, inspect every .mdc file under .cursor/rules/.
If strings such as alwaysApply: true, Run node .github/setup.js, or required for setup appear, treat the file as an instruction to the agent, not as plain documentation.
For VS Code, inspect .vscode/tasks.json together with runOptions.runOn, task.allowAutomaticTasks, and the Workspace Trust state.

Look for setup.js execution logs, outbound traffic from Node.js, unexpected GitHub repository creation, and use of GitHub, npm, Azure, GCP, AWS, Vault, or Kubernetes credentials.
This family does not stop at “which repository did you clone”; incident scope includes “which tool did you open it with.”

As with the Mini Shai-Hulud response, do not rotate credentials before stopping device-side monitors and persistence.
Prior waves observed logic that detects token revocation and enters destructive behavior.
Network isolation, removal of suspicious startup configuration, log preservation, and then credential rotation is the less destructive order for investigation.

Do not decide execution status from fixed filenames alone.
Treat the environment as Miasma-related if these behaviors line up.

Place to checkWhat to look for
Processesnode .github/setup.js spawned as a child process of Claude Code, Gemini CLI, Cursor, or VS Code
Temporary directoriesbun, bun-v1.3.13, .bun_ran, _index.js, *-setup.pth
GitHubSuspicious repositories with Miasma: The Spreading Blight or Hades - The End for the Damned in the description, results/results-*.json, or a Run Copilot job
Commitschore: update dependencies [skip ci], old-looking timestamps, configuration-only additions
Outbound trafficBun downloads, GitHub API repository/commit creation, unusual access to cloud metadata, Vault, or Kubernetes

Blocking only a legitimate-looking domain such as api.anthropic.com creates false positives.
Correlate the domain with the parent process of node or bun, the configuration file read immediately before execution, GitHub API activity, and the repository names that were created.

References