Skip to navigation

Threat reportSupply ChainTL-2026-5576

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

criticalACTIVE

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.

Key facts

IdentifiersTL-2026-5576
Also known asbee-js compromise, Swarm Desktop compromise, evjawbreaker, EtherDuck
SeverityCRITICAL
First disclosed
Affected productsEthersphere @ethersphere/bee-js (npm); Ethersphere Swarm Desktop; Ethersphere Dependents admitting bee-js 13.3.0 (swarm-cli 3.6.0/3.7.0, bee-dashboard 0.37.0/0.37.1, @snaha/swarm-id 0.5.0-0.8.0, file-manager-lib 1.1.0/1.1.1, bee-wasm-js 0.1.0/0.1.1, create-swarm-app)
Weaknesses (CWE)CWE-506
AttributionSleepyDuck, EtherDuck operator (high confidence)
MalwareUACMe, evjawbreaker
ToolsScreenConnect
MITRE ATT&CK techniquesT1005 Data from Local System, T1036 Masquerading, T1059.001 PowerShell, T1059.004 Unix Shell, T1059.007 JavaScript, T1071.001 Web Protocols, T1078 Valid Accounts, T1102.001 Dead Drop Resolver, T1195.002 Compromise Software Supply Chain, T1219 Remote Access Tools, T1497 Virtualization/Sandbox Evasion, T1543.001 Launch Agent and 8 more in the attack flow
MotivationFINANCIAL
Target sectorstechnology, software development, cryptocurrency, decentralized storage
Target regionsGlobal
Detection rules9 (1 shown free)
Sources7 cited sources

Detection coverage

As of 2026-11-09, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-5576 across Splunk SPL, Microsoft KQL and Sigma, covering 26 indicator(s) of compromise. The whole corpus is readable without an account. Every threat comes with one complete detection in Splunk SPL, Microsoft KQL and Sigma, free for everyone; a free account adds daily TL Creds to unlock the rest. Paid plans add a larger daily allowance, correlation and the MCP server. Threadlinqs MCP server · View plans.

Free detection: evjawbreaker Persistence on Linux/macOS (~/.solidity, systemd unit, LaunchAgent) — Post-Exploitation

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

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

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

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. Sign up free to unlock the detection rules or query them with the Threadlinqs MCP server (Purple)
  • Trojanized bee-js / Swarm Desktop Loader Execution and Stage-2 Retrieval (Defender XDR) — Exploitation · unlock with TL Creds
  • ScreenConnect Silent Install, Defender Exclusion and COR_PROFILER UAC Bypass Chain (Windows) — Post-Exploitation · unlock with TL Creds
  • evjawbreaker Hub, ScreenConnect Relay and Ethereum Dead-Drop Resolution (Defender XDR) — C2 · unlock with TL Creds
  • [indicator] Stage-2 Loader Server Lookup (Sigma) — Exploitation · unlock with TL Creds
  • ScreenConnect Silent MSI Install and Defender Exclusion by Loader (Sigma) — Post-Exploitation · unlock with TL Creds
  • Web Proxy Access to Loader, Payload and Wallet Exfiltration Endpoints (Sigma) — C2 / Exfiltration · unlock with TL Creds
  • Ethersphere bee-js 13.3.0 / Swarm Desktop 0.56.2 Loader Contacting [indicator] — Exploitation · unlock with TL Creds
  • Connections to evjawbreaker Hub and ScreenConnect Relay Infrastructure — C2 · unlock with TL Creds

Indicators of compromise

As of 2026-11-09, Threadlinqs Intelligence tracks 26 indicators of compromise for TL-2026-5576.

Sample indicators (3 of 26)

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

Defanged, TLP:CLEAR. Full set of 26 indicators: unlock with TL Creds.

26 indicators of compromise · unlock with TL Creds. Compare plans

Technical analysis

Pluto Security links the payloads, Ethereum C2 contract and persistence names, with high confidence, to the group behind the SleepyDuck/EtherDuck Open VSX campaigns.

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 techniques by tactic:

Collection

T1005 Data from Local System

Defense Evasion

T1036 Masquerading; T1497 Virtualization/Sandbox Evasion

Execution

T1059.001 PowerShell; T1059.004 Unix Shell; T1059.007 JavaScript

Command and Control

T1071.001 Web Protocols; T1102.001 Dead Drop Resolver; T1219 Remote Access Tools

Initial Access

T1078 Valid Accounts; T1195.002 Compromise Software Supply Chain

Persistence

T1543.001 Launch Agent; T1543.002 Systemd Service; T1543.003 Windows Service

Privilege Escalation

T1548.002 Bypass User Account Control

Credential Access

T1552.004 Private Keys

defense-impairment

T1553.001 Gatekeeper Bypass; T1553.002 Code Signing; T1685 Disable or Modify Tools

Resource Development

T1583.001 Domains

Remediation

Patches

  • Swarm Desktop 0.56.3 (clean, same code as 0.56.1, new Developer ID certificate); Linux installs do not auto-update and must be replaced manually
  • @ethersphere/bee-js 13.2.0 (13.3.0 removed from npm; GHSA lists no patched version)

Immediate actions

  • Search lockfiles, caches, internal registries, mirrors and CI logs for @ethersphere/bee-js@13.3.0 (integrity sha512-ltkrphoNy7TBIjCICDW7y3qa+j8yljt3+ohPRSM+id1rK2NaOgm5H5V/FioTQ0rEJ5IJ+Zj1micbAdQCqqc8iw==), pin 13.2.0 and purge cached copies
  • Treat any host or CI runner that installed 13.3.0 with install scripts enabled (2026-11-09 00:09:50-01:24:58 UTC) as compromised, even if the install failed; rotate reachable credentials from a clean machine, including cloud credentials reachable via CI OIDC trust
  • Check bee-desktop.log for 'Bee Desktop version: 0.56.2 (production)'; if present assume the node key and password were stolen and move wallet funds, chequebook and stake to a new key from a clean machine
  • Remove persistence: ~/.solidity/, systemd unit solidity-langsupport-runner.service, LaunchAgent com.solidity.langsupport.runner, Windows service 'ScreenConnect Client (5cbe79c9c25524df)'; prefer rebuilding from a trusted image
  • Block api.frameworkmetrics.xyz, 193.57.9.155, 185.232.84.169 and the other hub IPs at DNS, proxy and firewall

Workarounds

  • Install with --ignore-scripts until dependencies are verified
  • Alert on ScreenConnect installs not provisioned by IT and on relay 185.232.84.169:8041

Longer-term hardening

  • Require proof inside publishing workflows that the released commit is on a protected branch or a merged release PR; put publish environments behind required reviewers and restrict tag deployment
  • Do not expose signing and notarization credentials to manually dispatched workflows that accept arbitrary branches; scope and rotate release-bot tokens and alert on releases bypassing release-please
  • Disable dependency install scripts by default in CI (npm 12, pnpm 10+, Yarn Berry 4.14.0+, Bun and Deno already do)
  • Hunt for eth_call to contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 with data 0x02d91518 and poll the contract for new writes

Affected and fixed versions

  • Ethersphere — @ethersphere/bee-js (npm)
    Vulnerable versions: 13.3.0
    Fixed in: 13.2.0 (last clean)
  • Ethersphere — Swarm Desktop
    Vulnerable versions: 0.56.2
    Fixed in: 0.56.3
  • Ethersphere — Dependents admitting bee-js 13.3.0 (swarm-cli 3.6.0/3.7.0, bee-dashboard 0.37.0/0.37.1, @snaha/swarm-id 0.5.0-0.8.0, file-manager-lib 1.1.0/1.1.1, bee-wasm-js 0.1.0/0.1.1, create-swarm-app)
    Vulnerable versions: installs resolving @ethersphere/bee-js 13.3.0
    Fixed in: pin bee-js 13.2.0

Timeline

  • Operator deploys Ethereum config contract locked-ioc-11 (later used by SleepyDuck/EtherDuck waves and this campaign).
  • EtherDuck wave 1 fake Solidity extensions published to Open VSX using the same contract and payloads; removed about 19 hours later (Pluto Security report dated 2026-10-01).
  • locked-ioc-16 registered (15:08 UTC); failed secret-harvesting workflows POSTing to webhook.site collectors against swarm-desktop and swarm-cli (no evidence of successful exfiltration, per Socket).
  • At 23:30 UTC the operator writes hub locked-ioc-22:4912 to the contract; at 23:59:54 UTC unsigned commit de2f74e (as bee-worker) adds the loader to bee-js.
  • PR #582 merged and clean Swarm Desktop 0.56.3 released with a new Developer ID certificate; bee-js 13.2.0 is latest again; The Hacker News reports the incident.
  • Ethersphere deletes tag v0.56.2 at about 09:04 UTC (release non-public by about 09:14, about 8.5 hours after publication); about 65 downloads recorded by 08:27 UTC.
  • npm removes bee-js 13.3.0 at 01:24:58 UTC (about 75 minutes live); GitHub issues GHSA-hh7j-5m3j-23pf at 01:25 UTC.
  • Trojanized Swarm Desktop 0.56.2 released around 00:36 UTC, built, signed and Apple-notarized by 00:44 UTC; auto-updater offers it to Windows x64 and Apple Silicon users from 00:43 UTC.
  • bee-js release v13.3.0 created 00:06 UTC; npm publishes 13.3.0 at 00:09 UTC with valid provenance; the loader ran inside the publishing job three times.

Sources cited

Further reading

Drafted by the Threadlinqs research pipeline from 7 sources; published ; last updated —.

Threadlinqs Intelligence — Real-Time Threat Detection Platform

// threat_feed
$ sort --newest
Showing all threats

Live intelligence console

Threat level

Latest Threats