Back to Blog

@ethersphere/bee-js 13.3.0 Compromised

A compromised release of @ethersphere/bee-js executes malicious code during installation. The payloads target Swarm Desktop wallet data and attempt to establish persistent access on affected systems.
Ashish Kurmi
View LinkedIn

November 8, 2026

Share on X
Share on X
Share on LinkedIn
Share on Facebook
Follow our RSS feed
Table of Contents

StepSecurity AI Package Analyst discovered that @ethersphere/bee-js version 13.3.0 is compromised. Published to npm on November 9, 2026, at 00:09:50 UTC, the release downloads and executes attacker-controlled JavaScript during installation. The retrieved payloads target Swarm Desktop wallet files and attempt to install persistent access on Linux, macOS, and Windows.

The finding is available in the StepSecurity OSS Security Feed. We notified the maintainers through GitHub issue #1294 and reported the malicious release to npm.

The package recorded 3,560 downloads across all versions during November 1–7, 2026. That figure predates the malicious release and does not represent downloads of version 13.3.0 or the number of affected systems.

Action required: Do not install version 13.3.0. If it was installed with lifecycle scripts enabled, treat the system as potentially compromised while investigating whether the remote payload ran. Removing the package alone does not remove the persistence that the payload can install.

How the malicious release reached npm

The malicious changes appeared in commit de2f74e784b2eafa0d66fbb6d88b42ea11ee34cf, an unsigned direct commit to the upcoming branch under the bee-worker identity at 23:59:54 UTC on November 8. Its title, chore(upcoming): release 13.3.0, followed the project's release naming convention.

The normal release-please pull request for 13.3.0, #1288, was still open and unmerged when the report was prepared. The previous release, 13.2.0, had gone through a signed, merged release pull request. The reviewed GitHub Actions history did not contain a run that created the malicious commit.

The v13.3.0 GitHub release was published under the bee-worker identity at 00:06:01 UTC on November 9. That triggered the repository's existing npm publishing workflow, which published the compromised package using GitHub Actions trusted publishing.

The npm package therefore carries valid SLSA provenance linking it to the legitimate repository and workflow. The malicious code was already in the source that the workflow built.

The evidence points to misuse of the bee-worker release identity. A stolen account credential or token is a likely explanation, but the available evidence does not establish which credential was used or how it was obtained.

The installation hook

The release changed package.json in two places: it moved node scripts/generate-version.cjs from prepare to postinstall, and it added the scripts directory to the files shipped in the npm package. These changes made the modified script available to, and executable during, consumer installations.

The script requests /v1/analytics from api.frameworkmetrics[.]xyz. It sends X-Ethersphere: 1 and uses the operating system name—linux, darwin, or win32—as its User-Agent. The server uses that value to return a platform-specific JavaScript payload.

The response is executed through JavaScript's Function constructor with access to Node.js require and process. This gives the downloaded code access to files, processes, and the network with the installing user's permissions. Importing or using the library is not required.

Comments describe the request as an “analytics ping.” The code uses a three-second timeout and suppresses request errors. It also runs before the version-generation script's normal check for a source directory, so the absence of source files in a consumer installation does not prevent the request.

Swarm Desktop wallet theft

The Linux, macOS, and Windows JavaScript payloads look for two files in the Swarm Desktop data directory:

  • config.yaml
  • data-dir/keys/swarm.key

If both files exist, the payload reads them and sends their contents as JSON fields named configYaml and v3 to /v1/swarm/report on the same attacker-controlled host.

The swarm.key file is an encrypted Ethereum V3 keystore. The configuration can contain the password needed to decrypt it. When that password is present, stealing both files can give the attacker control of the wallet.

This establishes the wallet-theft behavior in the retrieved code. The report does not establish how many wallets were exposed or whether funds were stolen.

Persistent access by platform

Linux

The Linux payload downloads an x86-64 or ARM64 executable into ~/.solidity/, creates a Python launcher named .run.py, and configures the user service solidity-langsupport-runner.service. The service describes itself as a “Solidity language tooling helper” and is configured to restart on failure. The script also attempts to launch the executable immediately.

Both Linux executables were retrieved during the original investigation. Static inspection identified Go package and function names associated with a hub client, command execution, and interactive shells, including hubclient.runCommand, hubclient.startShellLocked, and github.com/creack/pty.

These findings support the assessment that the executables provide remote access. They were not executed, so their runtime behavior and full command set have not been verified.

macOS

The macOS script downloads an architecture-specific executable into ~/.solidity/ and creates a Node.js or Python launcher. It writes ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist with RunAtLoad enabled, clears extended attributes from the executable, and attempts to start it through launchctl.

The JavaScript establishes the download and persistence behavior. The macOS executable itself was not retrieved, so its capabilities remain unverified.

Windows

The Windows script checks for an existing installation whose directory name contains ScreenConnect. It then attempts to retrieve invoke.ps1 and app.msi and stages PowerShell and VBScript launchers under %TEMP% using .stuffed-* filenames.

Its installation sequence creates a hidden directory under %LOCALAPPDATA%, adds a Microsoft Defender exclusion for that directory, and runs the MSI silently. Cleanup code removes the exclusion and staging files afterward.

Neither invoke.ps1 nor app.msi was retrieved. The ScreenConnect check suggests a remote-access installer, but the MSI's identity and the helper's elevation mechanism have not been confirmed.

Affected packages and dependencies

The confirmed malicious release is @ethersphere/bee-js@13.3.0. The examined 13.2.0 release lacks the malicious installation path.

Other projects can receive 13.3.0 through their dependency ranges. The report identified these examples:

ProjectVersion examinedDependency on @ethersphere/bee-js
@ethersphere/swarm-cli3.7.0^13.2.0
@ethersphere/bee-dashboard0.37.1^13.0.0
swarm-desktop repositoryRepository configuration^13.0.0

These ranges permit 13.3.0. A fresh dependency resolution or lockfile update could select the malicious version while it was available. This does not establish that these projects' own packages contain injected code or that every installation received 13.3.0; the resolved dependency version matters.

At 00:31 UTC on November 9, npm still mapped latest to 13.3.0. This is the registry state recorded during the investigation, not a claim about its current availability.

Timeline

All times are UTC.

TimeEvent
November 6, 15:08frameworkmetrics[.]xyz registered.
November 8, 23:59:54Malicious commit added under the bee-worker identity; GitHub release record created.
November 9, 00:06:01GitHub release v13.3.0 published.
November 9, 00:06:03The legitimate npm publishing workflow started.
November 9, 00:09:50@ethersphere/bee-js@13.3.0 published to npm.
November 9, approximately 00:28–00:29Platform-specific JavaScript and Linux executables retrieved during the investigation.
November 9, approximately 00:31Requests to the payload infrastructure returned benign decoy content or HTTP 404 responses.

Indicators of compromise

Network and files

IndicatorPurpose
api.frameworkmetrics[.]xyzPayload delivery and wallet-data exfiltration
/v1/analyticsPlatform-specific JavaScript delivery
/v1/assets/Additional payload downloads
/v1/swarm/reportWallet-data exfiltration
X-Ethersphere: 1 with User-Agent linux, darwin, or win32Requests made by the installation hook and payloads
~/.solidity/linux_amd64 or linux_arm64; ~/.solidity/.run.pyLinux executable and launcher
~/.config/systemd/user/solidity-langsupport-runner.serviceLinux persistence
~/.solidity/darwin_arm64 or darwin_amd64; .run.cjs or .run.py in the same directorymacOS executable and launcher
~/Library/LaunchAgents/com.solidity.langsupport.runner.plistmacOS persistence
%TEMP% files beginning .stuffed-Windows staging files
%LOCALAPPDATA%\.<32-hex-guid>\app.msiWindows installer staging; the script attempts to delete it afterward

Linux executable hashes

FileSHA-256
linux_amd649b73e7cd4e1425e770392549d8df46c706139ef476f4f7b9ac405165dc8d9696
linux_arm64b601776817363b96295119f7221338a122d5247a35a77a64b04f286e1bbcc565

The malicious npm tarball's SHA-1 is a205c8a5fed81e9a787645b2801f00be3db3348d.

What to check and how to respond

Check lockfiles, installed dependency metadata, and CI installation logs for @ethersphere/bee-js@13.3.0, including transitive dependencies. Determine whether installation scripts were enabled and review DNS, proxy, and endpoint records for the indicators above. A successful installation log does not rule out execution: the hook suppresses network errors.

If the remote payload ran, isolate the host and treat it as compromised. Preserve evidence, investigate the persistence locations, and rebuild affected systems from a trusted image. Replacing the npm dependency does not undo code that has already run or remove an installed service or LaunchAgent.

Rotate credentials that were accessible to the affected user or CI job from a clean environment. If Swarm Desktop wallet files were present, treat the keystore and any password in config.yaml as exposed and replace the affected wallet using a clean system.

Remove 13.3.0 from dependency resolution and pin a reviewed release. The examined 13.2.0 package does not contain this malicious installation hook. Blocking lifecycle scripts prevents this particular hook from running during installation, but does not remediate an earlier execution.

The investigation has not established the initial credential-theft method, the number of affected installations, or the full capabilities of the unretrieved payloads. We will update this report as those findings are confirmed.

‍

Explore Related Posts

‍