# Ethersphere bee-js 13.3.0 and Swarm Desktop 0.56.2 Supply-Chain Compromise Delivers Wallet-Stealing Malware and Backdoors

> On 2026-11-09 attackers using compromised GitHub accounts (a maintainer and the bee-worker release bot) abused Ethersphere's release/CI workflows to publish malicious @ethersphere/bee-js 13.3.0 (npm, valid provenance) and a signed, notarized Swarm Desktop 0.56.2. A loader fetches JavaScript from api.frameworkmetrics.xyz, steals Swarm node wallet files (swarm.key, config.yaml) and installs the Go backdoor evjawbreaker on Linux/macOS or a ScreenConnect client on Windows. Pluto Security links the payloads, Ethereum C2 contract and persistence names, with high confidence, to the group behind the SleepyDuck/EtherDuck Open VSX campaigns.

- **Published:** 2026-11-09T18:35:48Z
- **Last reviewed:** 2026-11-09T18:35:48Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-5576
- **Card image:** https://intel.threadlinqs.com/og/threat/TL-2026-5576.png
- **ID:** TL-2026-5576
- **Severity:** CRITICAL
- **Category:** SUPPLY_CHAIN
- **Status:** ACTIVE
- **Actor:** SleepyDuck
- **Detections:** 9 (1 shown free below) · **IOCs:** 26 (3 shown free below)

## Description

Supply-chain compromise of the Ethersphere (Swarm) ecosystem. Two GitHub accounts were compromised: a maintainer account with force-push rights to an unprotected master branch, and the release automation identity bee-worker. Socket reports failed secret-harvesting attempts against swarm-desktop and swarm-cli on 2026-11-06 (workflows POSTing secrets to webhook.site collectors, no evidence of successful exfiltration), and the origin of the account compromises is unexplained. The domain frameworkmetrics.xyz was registered on 2026-11-06, and on 2026-11-08 the operator wrote the new hub address 193.57.9.155:4912 to an Ethereum configuration contract.

bee-js: at 2026-11-08 23:59:54 UTC an unsigned commit (de2f74e, authored as bee-worker, copying a release-please PR title but never submitted as a PR) renamed the package's prepare hook to postinstall and added scripts to the published files list. scripts/generate-version.cjs gained a loader at the top that sends an HTTPS GET to api.frameworkmetrics.xyz/v1/analytics (3s timeout, User-Agent = process.platform, header X-Ethersphere: 1) and runs the response via new Function('require','console','process',body). A GitHub release created on the unsigned tag triggered the Publish on npm workflow, which required no approval and skipped tests; npm received 13.3.0 at 00:09 UTC with valid SLSA provenance because the legitimate workflow built it. It was latest for about 75 minutes (removed 01:24:58 UTC; GHSA-hh7j-5m3j-23pf, CWE-506). Dependents admitting 13.3.0 include swarm-cli, bee-dashboard, @snaha/swarm-id, file-manager-lib, bee-wasm-js and create-swarm-app.

Swarm Desktop 0.56.2: commit 2de7270 on an emergency/0.56.2 branch added a 731-byte loader to src/index.ts, executed as the first action of main() on every launch with path /v1/electron. The attacker manually dispatched pre-release.yml, which had access to the Apple and Windows signing certificates and notarization credentials with no approval, producing a signed and Apple-notarized build. The built-in updater offered it to Windows x64 and Apple Silicon users within minutes; the release stayed public about 8.5 hours (about 65 downloads by 08:27 UTC). Clean 0.56.3 (same code as 0.56.1, new Developer ID certificate) replaced it.

Stage 2 returns a decoy unless X-Ethersphere: 1 is present, otherwise OS-specific JavaScript that locates Swarm Desktop's data directory and POSTs config.yaml (plaintext keystore password) and data-dir/keys/swarm.key to /v1/swarm/report, exposing node wallet xDAI/xBZZ, chequebook funds and stake, then downloads stage 3 from /v1/assets/. On Linux/macOS stage 3 is the Go remote shell evjawbreaker stored in ~/.solidity/ (launched by .run.py or .run.cjs), persisting via systemd user unit solidity-langsupport-runner.service or LaunchAgent com.solidity.langsupport.runner (quarantine attribute cleared), exiting if a debugger/VM is detected, reading its hub address from the Ethereum contract via public RPC gateways (rpc.ankr.com, cloudflare-eth.com; getter selector 0x02d91518) and connecting over TLS without certificate validation to a persistent sh pseudo-terminal. On Windows an obfuscated PowerShell loader (invoke.ps1) uses UACME method 39 (COR_PROFILER hijack against mmc.exe) for admins, or repeated UAC prompts for standard users, adds a Defender exclusion, silently installs a ConnectWise-signed ScreenConnect 25.4.3 client (app.msi) configured for relay 185.232.84.169:8041 as SYSTEM service 'ScreenConnect Client (5cbe79c9c25524df)', then removes the exclusion and staging files.

Attribution: the Ethereum contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 (deployed 2026-03-14) is the same one Pluto Security documented in the SleepyDuck/EtherDuck Open VSX campaign; six of seven Pluto payload hashes match files served by the bee-js C2, and persistence names, ScreenConnect instance ID and relay are identical. The 'Solidity language support' naming is carried over from that campaign. The maintainers' note attributes the release to stolen CI credentials/secrets; how they were stolen is not established. Ethersphere now requires DevOps approval for signing jobs, restricted to main. Because the C2 hub is held in a mutable on-chain contract there is no domain to seize.

## MITRE ATT&CK

- T1583.001 Domains
- T1195.002 Compromise Software Supply Chain
- T1078 Valid Accounts
- T1059.007 JavaScript
- T1059.001 PowerShell
- T1059.004 Unix Shell
- T1543.001 Launch Agent
- T1543.002 Systemd Service
- T1543.003 Windows Service
- T1548.002 Bypass User Account Control
- T1553.002 Code Signing
- T1553.001 Gatekeeper Bypass
- T1685 Disable or Modify Tools
- T1497 Virtualization/Sandbox Evasion
- T1036 Masquerading
- T1552.004 Private Keys
- T1005 Data from Local System
- T1102.001 Dead Drop Resolver
- T1071.001 Web Protocols
- T1219 Remote Access Tools

## Free detection (Splunk SPL, Microsoft KQL, Sigma)

**evjawbreaker Persistence on Linux/macOS (~/.solidity, systemd unit, LaunchAgent) — Post-Exploitation** (`TL-2026-5576-SPL-002`)

Detects installation and launch of the Go backdoor evjawbreaker delivered by the TL-2026-5576 stage 3: files written under ~/.solidity/ (platform binaries plus .run.py/.run.cjs launchers), the systemd user unit solidity-langsupport-runner.service, the macOS LaunchAgent com.solidity.langsupport.runner, and clearing of the quarantine attribute on the install directory. The 'Solidity language support' naming masquerades as a developer tool and is carried over from the SleepyDuck/EtherDuck Open VSX campaign.

- **Languages:** Splunk SPL, Microsoft KQL, Sigma
- **ATT&CK:** T1543.002, T1543.001, T1553.001, T1036
- **Data sources:** sysmon_for_linux, edr_file_events
- **Severity:** critical
- **Confidence:** high

### Splunk SPL

```spl
index=linux sourcetype="sysmon:linux" earliest=-24h (((EventCode=11 OR EventID=11) (TargetFilename="*/.solidity/*" OR TargetFilename="*solidity-langsupport-runner.service" OR TargetFilename="*com.solidity.langsupport.runner.plist")) OR ((EventCode=1 OR EventID=1) (Image="*/.solidity/*" OR CommandLine="*systemctl*--user*solidity-langsupport-runner*" OR CommandLine="*launchctl*com.solidity.langsupport.runner*" OR CommandLine="*/.solidity/.run.py*" OR CommandLine="*/.solidity/.run.cjs*" OR (CommandLine="*xattr*" CommandLine="*com.apple.quarantine*" CommandLine="*.solidity*"))))
| eval signal=case(isnotnull(TargetFilename) AND like(TargetFilename,"%.service"),"systemd_user_unit_written", isnotnull(TargetFilename) AND like(TargetFilename,"%.plist"),"launchagent_written", isnotnull(TargetFilename),"solidity_dir_file_written", like(CommandLine,"%xattr%"),"quarantine_attribute_cleared", true(),"solidity_launcher_or_service_started")
| stats count min(_time) as firstTime max(_time) as lastTime values(signal) as signals values(Image) as processes values(CommandLine) as command_lines values(TargetFilename) as files by host, User
| eval firstTime=strftime(firstTime,"%Y-%m-%d %H:%M:%S"), lastTime=strftime(lastTime,"%Y-%m-%d %H:%M:%S")
| table host User signals processes command_lines files count firstTime lastTime
```

### Microsoft KQL

```kql
let lookback = 24h;
let files = DeviceFileEvents
| where Timestamp > ago(lookback)
| where ActionType in ('FileCreated', 'FileModified', 'FileRenamed')
| where FolderPath has '/.solidity/' or FileName =~ 'solidity-langsupport-runner.service' or FileName =~ 'com.solidity.langsupport.runner.plist'
| project Timestamp, DeviceName, AccountName=InitiatingProcessAccountName, Signal='evjawbreaker_persistence_file', Process=InitiatingProcessFileName, CommandLine=InitiatingProcessCommandLine, Detail=FolderPath;
let procs = DeviceProcessEvents
| where Timestamp > ago(lookback)
| where FolderPath has '/.solidity/'
    or ProcessCommandLine has_any ('solidity-langsupport-runner', 'com.solidity.langsupport.runner', '.solidity/.run.py', '.solidity/.run.cjs')
    or (ProcessCommandLine has 'xattr' and ProcessCommandLine has 'com.apple.quarantine' and ProcessCommandLine has '.solidity')
| project Timestamp, DeviceName, AccountName, Signal='evjawbreaker_launch_or_service_control', Process=FileName, CommandLine=ProcessCommandLine, Detail=FolderPath;
union files, procs
| summarize FirstSeen=min(Timestamp), LastSeen=max(Timestamp), Events=count(), Signals=make_set(Signal), Processes=make_set(Process, 10), Details=make_set(Detail, 10) by DeviceName, AccountName
| order by LastSeen desc
```

### Sigma

```yaml
title: evjawbreaker Backdoor Persistence Artifacts on Linux (~/.solidity and systemd User Unit)
id: 9c4d8e12-3a57-4b0f-8e26-1f7a5d3b2c02
status: experimental
description: Detects creation of the ~/.solidity/ install directory content and the solidity-langsupport-runner.service systemd user unit used by the evjawbreaker Go backdoor dropped by the trojanized Ethersphere bee-js 13.3.0 / Swarm Desktop 0.56.2 (TL-2026-5576, SleepyDuck/EtherDuck).
references:
  - https://socket.dev/blog/bee-js-compromise
  - https://pluto.security/blog/sleepyduck-malware-open-vsx-extensions/
author: Threadlinqs Team
date: 2026-11-09
tags:
  - attack.persistence
  - attack.t1543.002
  - attack.defense-evasion
  - attack.t1036
logsource:
  category: file_event
  product: linux
detection:
  selection_dir:
    TargetFilename|contains: '/.solidity/'
  selection_unit:
    TargetFilename|endswith: 'solidity-langsupport-runner.service'
  condition: 1 of selection_*
falsepositives:
  - A developer tool legitimately using a ~/.solidity directory (verify the file names and the presence of .run.py or .run.cjs)
level: high
```

**Known false positives:**

- Legitimate Solidity tooling that creates a ~/.solidity directory (check for .run.py/.run.cjs launchers and platform-named Go binaries)
- Security researchers detonating the sample in a lab

**Tuning notes:** Adjust index and sourcetype to your Linux telemetry (Sysmon for Linux, auditd or EDR) and add macOS endpoint-security data so the LaunchAgent and xattr branches fire. The unit, plist and launcher names are specific, so little tuning is needed beyond excluding known Solidity developer tooling.

### 8 more detection rules (Splunk SPL, Microsoft KQL, Sigma), unlock with TL Creds

- Trojanized bee-js / Swarm Desktop Loader Execution and Stage-2 Retrieval (Defender XDR) — Exploitation (locked: unlock with TL Creds)
- ScreenConnect Silent Install, Defender Exclusion and COR_PROFILER UAC Bypass Chain (Windows) — Post-Exploitation (locked: unlock with TL Creds)
- evjawbreaker Hub, ScreenConnect Relay and Ethereum Dead-Drop Resolution (Defender XDR) — C2 (locked: unlock with TL Creds)
- [indicator] Stage-2 Loader Server Lookup (Sigma) — Exploitation (locked: unlock with TL Creds)
- ScreenConnect Silent MSI Install and Defender Exclusion by Loader (Sigma) — Post-Exploitation (locked: unlock with TL Creds)
- Web Proxy Access to Loader, Payload and Wallet Exfiltration Endpoints (Sigma) — C2 / Exfiltration (locked: unlock with TL Creds)
- Ethersphere bee-js 13.3.0 / Swarm Desktop 0.56.2 Loader Contacting [indicator] — Exploitation (locked: unlock with TL Creds)
- Connections to evjawbreaker Hub and ScreenConnect Relay Infrastructure — C2 (locked: unlock with TL Creds)

Sign up free to unlock the detection rules: https://threadlinqs.com/?modal=signup

## Sample indicators (3 of 26)

Defanged, TLP:CLEAR.

- IP address: `193.57.9[.]155`
- Domain: `frameworkmetrics[.]xyz`
- File hash: `9b73e7cd4e1425e770392549d8df46c706139ef476f4f7b9ac405165dc8d9696`

Full set of 26 indicators unlocks with TL Creds: https://threadlinqs.com/tl-creds

## Sources

- [The Hacker News: Hackers Compromise Ethersphere's bee-js and Swarm Desktop to Deliver Wallet-Stealing Malware](https://thehackernews.com/2026/11/hackers-compromise-etherspheres-bee-js.html)
- [GitHub Advisory GHSA-hh7j-5m3j-23pf (bee-js 13.3.0)](https://github.com/advisories/GHSA-hh7j-5m3j-23pf)
- [Socket: Malicious @ethersphere/bee-js 13.3.0 and Swarm Desktop 0.56.2](https://socket.dev/blog/bee-js-compromise)
- [SafeDep: Compromised bee-js 13.3.0 and Swarm Desktop 0.56.2](https://safedep.io/blog/ethersphere-bee-js-npm-compromise)
- [Swarm Desktop clean release v0.56.3](https://github.com/ethersphere/swarm-desktop/releases/tag/v0.56.3)
- [Maintainer incident note: swarm-desktop PR 582 (replace compromised 0.56.2 release)](https://github.com/ethersphere/swarm-desktop/pull/582)
- [Pluto Security: SleepyDuck/EtherDuck malware in Open VSX extensions](https://pluto.security/blog/sleepyduck-malware-open-vsx-extensions/)

## Full data

The other 8 detection rules (Splunk SPL / Microsoft KQL / Sigma) unlock with TL Creds; a free account includes daily creds: https://threadlinqs.com/?modal=signup
Indicator values unlock with TL Creds, at a lower price on Red and Purple; AI agents can query rules and IOCs through the Threadlinqs MCP server (Purple): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-5576
