背景

Solidity Pro 是一款面向 Solidity/Web3 开发者的 VS Code 扩展,对外定位为开发辅助工具,提供 Gas 查询、代币价格、代码片段和编译提示等功能,其 GitHub 仓库还曾宣传 AI Audit、Security Scanner 等安全能力。

在公开活动中,Solidity Pro 先后使用过 helper-beeps 和 web3devtoolsx 两个 publisher(发布者身份),对应的 Extension ID(扩展唯一标识)分别为 helper-beeps.solidity-pro 和 web3devtoolsx.solidity-pro。虽然发布身份发生了变化,但后续构建产物中仍保留旧 publisher、仓库地址和版权信息,表明两者之间存在直接的工程继承关系。

2026 年 8 月 6 日至 7 日,这两个 Extension ID 先后被加入 Open VSX 使用的恶意扩展控制列表。按理说,继续沿版本向后检查应该仍能看到相关恶意能力,但我们取得的 Solidity Pro 4.0.0(publisher:web3devtoolsx)却呈现出完全不同的结果:最终 bundle(打包后的执行代码)中只剩 Gas、代币价格、日志等普通功能,历史恶意版本中出现过的凭据采集、远程载荷下载、子进程执行和远程 VSIX 更新模块均已消失。

于是问题变成了:一个已经存在明确恶意历史的插件,为什么在后续版本中又变得“干净”?

本文将从 4.0.0 向前回溯 Solidity Pro 的版本与发布身份变化,分析两个历史恶意版本、GitHub Clean commit、publisher 迁移和公开活动时间线,并讨论仅根据当前版本判断 IDE 扩展风险可能产生的检测盲区。

本文分析基于静态证据,未运行样本或连接远端基础设施。

MistEye 响应

MistEye 是由 SlowMist 自主研发的 Web3 威胁情报与动态安全监控平台,集成了安全监控与情报聚合能力,为用户提供实时的风险预警与资产守护。

MistEye 对 helper-beeps.solidity-pro 与 web3devtoolsx.solidity-pro 两个发布身份及对应样本进行了关联梳理。结合静态去混淆、恶意能力交叉复核和公开平台时间线,提取了样本哈希、扩展 ID、危险请求路径与远程更新行为,用于 IDE 扩展供应链风险预警。

https://enterprise.misteye.io/threat-intelligence/SM-2026-905620

一、当前版本

要判断 4.0.0 为什么没有命中恶意代码,需要同时检查两个对象:本文取得的 4.0.0 样本,以及与其 bundle 一致的 GitHub 仓库状态。

VSIX 包里有什么。 本地重建的 4.0.0 包的最终 bundle 主要包含 ApiClient、GasTracker、PriceMonitor 和 Logger,网络访问集中在 Etherscan 与 CoinGecko。扩展在 onStartupFinished 或包含 Solidity 文件的工作区激活后,仅启动 Gas tracker、Price monitor 和 logger,并注册三个公开命令;compile 命令只显示一条 Hardhat/Foundry 提示,不实际调用编译器。在已检查文件和静态可达路径中,未发现历史版本中的凭据采集、远程载荷下载、子进程执行和远程 VSIX 更新四类恶意能力。

GitHub 仓库里还有什么。 4.0.0 包本身没有携带源码,因此我们进一步向 GitHub 回溯其公开工程。仓库中一个 package.json 版本回退为 v1.0.0、commit 95dce4f、提交信息为 "Clean release" 的提交,其 out/extension.js 与 4.0.0 bundle 均为 10,633 字节、SHA-256 一致。

该 commit 的 out/extension.js 同样只包含 ApiClient、GasTracker、PriceMonitor 和 Logger,激活与停用函数仅做初始化与清理。但同一 commit 的 src/ 目录却是另一番景象:src/telemetry/Web3Analytics.ts 仍在,文件头写着 "Sends install ping immediately, then scans for secrets",内部包含 BIP39 词表、钱包凭据识别、WORKERS 外传配置和大规模文件搜集上限;src/services/AutoUpdater.ts 同样保留,定义了 30 分钟周期的版本检查与远程 VSIX 安装逻辑。

GitHub 仓库 (Clean commit 95dce4f)
├── src/telemetry/Web3Analytics.ts   # 恶意采集工程源码仍在
├── src/services/AutoUpdater.ts  # 远程 VSIX 更新源码仍在
├── .vscodeignore                # 排除 src/**、scripts/**、*.ts
└── out/extension.js             # 打包时可见的干净 bundle

恶意源码为什么没有进入 VSIX 包?这里存在两道边界。

第一道是执行入口:Clean commit 的 src/extension.ts 删除了对 Web3Analytics 与 AutoUpdater 的 import 和启动逻辑,esbuild 从该入口构建依赖图时,不再将这两个模块编入 out/extension.js。

第二道是包内可见性:.vscodeignore 排除了 src/**、scripts/** 和 *.ts,同时保留 out/**,因此残留的 TypeScript 源文件也不会以原始源码形式进入按该配置生成的 VSIX。v1.0.0 的提交信息写的是 "Clean release",但恶意模块源文件未在该 commit 中删除或修改——最终交付物变干净了,工程内部的恶意模块仍可在后续源码或构建配置变更中被重新纳入。

恶意模块源码仍在仓库中,.vscodeignore 将其排除在按该配置生成的 VSIX 之外

二、历史恶意版本

既然当前版本和 Clean commit 的 bundle 均未发现原恶意模块,调查需要继续追踪 Solidity Pro 在两个发布身份下出现的历史版本。

Solidity Pro 并不是始终使用同一种恶意实现。在 helper-beeps 发布身份下取得的 2.4.1 与 web3devtoolsx 发布身份下取得的 3.4.0,展示了两套明显不同的执行方式:前者以延迟下载和远程代码执行为核心,后者以内置凭据采集和远程更新通道为核心。

2.4.1:延迟投递

在本文取得的 Solidity Pro 2.4.1 样本中(publisher:helper-beeps),扩展在 Solidity 文件或 Hardhat/Foundry 工作区中激活,telemetry 默认开启。激活后代码不会立即进入下载阶段,而是设置一段 24 至 48 小时的随机等待窗口:

MIN_DELAY_MS: 86400000,
MAX_DELAY_MS: 172800000

等待结束后,代码对 CI、GITHUB_ACTIONS、JENKINS_HOME、GITPOD_WORKSPACE_ID 等环境变量做存在性判断,命中即退出。随后对六个编码的主目录相对路径逐一执行 fs.existsSync 筛选,这些路径在该阶段只用于存在性筛选。

通过筛选后,代码依次尝试两个编码端点,向每个端点请求固定路径 /firmware。获得响应后校验长度,使用 crypto.createDecipheriv 以 AES-GCM 解密,将解密文本以受限权限写入临时目录的 .py 文件,再通过 child_process.spawn 以 detached 方式执行。约 60 秒后 unlinkSync 清理临时文件。未取得 /firmware 实际响应,二阶段具体功能未知。

本地随机延迟、环境筛选、远端密文获取、解密与 Python 子进程执行链

3.4.0:凭据采集

Solidity Pro 3.4.0(publisher: web3devtoolsx)的 package.json 的 activationEvents 同时声明了 workspaceContains:*.sol 和 onStartupFinished。扩展可在 VS Code 启动完成后自动进入 activate(),不要求用户执行其公开命令。

默认配置 solidity-pro.telemetry.enabled=true 会创建并启动 Web3Analytics。README 声称仅收集匿名使用数据、不存储私钥或源码,但该模块实际执行的扫描对象覆盖了开发者信任域的核心资产:

  • 钱包与签名材料:EVM 私钥、BIP39 助记词、keystore、Solana id.json、浏览器钱包扩展数据(MetaMask、Phantom、Coinbase Wallet、Rabby)。

  • 源码与发布凭据:GitHub ghp_/gho_/github_pat_ token、GitLab glpat-、.npmrc、PyPI token、.netrc、Git 凭据。

  • 云与基础设施:AWS access/secret/session key、Kubernetes config、Docker 认证、Azure、GCP 配置。

  • 项目与交互痕迹:.env 及变体、API key、AI 服务 token(sk-、sk-proj-、sk-ant-)、Shell 历史和主机信息。

EVM 私钥的正则匹配覆盖了 privateKey、PRIVATE_KEY、WALLET_KEY、DEPLOYER_KEY 等常见变量名和 64 位十六进制值:

var _0x4e0bcc = [
  /["']privateKey["']\s*:\s*["'](?:0x)?([0-9a-fA-F]{64})["']/g,
  /(?:PRIVATE_KEY|PRIVATEKEY|ETH_KEY|ETHKEY|WALLET_KEY|WALLETKEY|DEPLOYER_KEY|OWNER_KEY)\s*=\s*["']?(?:0x)?([0-9a-fA-F]{64})["']?/gi,
  /(?:privateKey|private_key|ethKey|eth_key|walletKey|wallet_key)\s*[:=]\s*["'](?:0x)?([0-9a-fA-F]{64})["']/gi,
  /(?:priv(?:ate)?[ _-]?key|secret)[:=]\s*["']?(0x[0-9a-fA-F]{64})["']?/gi
];

SSH 目录采集逻辑会枚举 ~/.ssh/ 中的候选私钥文件,读取内容并交给 extractSecrets 提取器。采集结果通过两条 HTTP 请求路径向外发送:文本 JSON 经 HTTPS 向混淆的 CFG.WORKERS 主机 POST /x,完整报告以 multipart/form-data 向同一组主机 POST /y。

与该采集链并行运行的还有 AutoUpdater。它在 activate() 中被无条件创建并启动,不依赖 telemetry 配置。启动后立即请求一次 /version,此后每 30 分钟轮询两个硬编码 Worker;只要响应里带有 version 和 url,代码就比对版本号、下载 VSIX、调用 VS Code 安装命令,再删除临时文件。

整条更新链没有任何完整性校验——更新器自身未实现哈希、签名、publisher 或证书固定。这意味着服务端可以在任意一次轮询中返回更高版本和下载地址,自行决定什么时候触发更新、投递哪个 VSIX。更关键的是,更新前只会弹出一个仅有 "OK" 按钮的通知,代码等通知流程结束后就继续安装,既没有真正的取消选项,也不读取用户的选择结果。

这类采集目标之所以危险,在于 IDE Extension Host 本身位于开发者信任域内部。Web3 开发机往往同时保存钱包材料、源码仓库凭据、包发布 token、CI/CD 和云平台配置,一次扩展供应链攻击可能同时跨越多个安全边界。

四类样本或版本的角色对照:

VS Code 启动后自动触发的凭据采集、/x 与 /y 外传,以及独立运行的远程 VSIX 更新通道

三、发布者迁移

Solidity Pro 的 2.4.1 与 3.4.0 并不属于同一个 Extension ID。前者由 helper-beeps 发布,后者则使用新 publisher web3devtoolsx。为什么还能把它们放在同一条调查线上?

初始 v3.4.0 commit fe794a2 的内部元数据直接回答了这个问题。package.json 声明 publisher: web3devtoolsx、版本 3.4.0,repository 指向 github.com/web3devtoolsx/solidity-pro。同一 commit 的 out/package.json 却保留 publisher: helper-beeps、版本 3.3.0,repository 指向 github.com/helper-beeps/solidity-pro。LICENSE 文件仍写着 "Copyright (c) 2026 Helper Beeps"。

两份 package.json 出自同一次提交,证明 Solidity Pro 在 web3devtoolsx 身份下的初始构建产物直接来自 helper-beeps 工程,代码或构建产物存在直接来源关联。

将构建产物继承关系与官方恶意标记时间线叠加后,publisher 轮换的模式更加清晰:

helper-beeps.solidity-pro 被加入官方 malicious 列表 (2026-08-06 14:27:24 UTC)
    │ 8 小时 32 分 48 秒
    ▼
web3devtoolsx GitHub 账号创建 (2026-08-06 23:00:12 UTC)
    │ 约 16 分钟
    ▼
新的 Solidity Pro v3.4.0 出现
    │ 次日
    ▼
web3devtoolsx.solidity-pro 也被加入官方 malicious 列表 (2026-08-07 12:38:52 UTC)

初始提交中旧 publisher、版本、仓库地址和版权残留证明构建产物存在直接来源关联

四、Clean release

GitHub 初始 commit 提交恶意 v3.4.0 bundle 后仅 13 分 29 秒,同一仓库提交了版本回退为 v1.0.0 的 Clean commit。在这段极短窗口内,发布者还短暂发起并自行关闭了 Open VSX namespace claim(issue 无评论,由 web3devtoolsx 本人关闭)。

Clean commit 的修改精确集中在两类目标。执行面移除了 Web3Analytics 激活、AutoUpdater 启动、telemetry 配置、javascript-obfuscator 依赖和混淆构建步骤。产品表面移除了 AI Audit Engine、Security Scanner、100K+ badge 和夸大能力文案。版本号从 3.4.0 回退到 1.0.0。

这些变化集中出现在同一个名为 "Clean release" 的提交中。它直接移除了公开可达的高风险入口和部分显眼营销文案,使只检查新 bundle 的系统不再命中原恶意模块。清理并不彻底: package.json description 中的 "Trusted by 100K+" 和 "vulnerability scanner" 表述未被移除——最显眼的 badge 被删掉,若该 manifest 被实际打包并发布,能影响搜索结果和商店页面的元数据仍在。而如前所述,恶意源码仍完整保留在 src/ 目录下,只是通过 .vscodeignore 不进入最终包。

Clean release 改变的是最终交付物,而不是这个工程已经发生过的历史。

五、可信度包装

与版本变化几乎同时发生的,还有新发布身份的快速包装:web3devtoolsx 账号创建后约 16 分钟内,企业样式资料、六个知名项目 fork、产品仓库、成熟版本号和 100K+ 声明集中出现。这些信号集中出现,客观上会让新账号呈现较成熟的组织外观。

企业样式资料。 账号创建约 15 分钟后,Profile 已包含 "Web3 Dev Tools" 名称、公司字段、Zug 地点、官网、Twitter 链接、一个已上线产品和两个 "Coming Q3" 产品路线图。截至 2026 年 8 月 12 日复核,followers、following、gists 等长期活动指标仍为 0。

六个知名项目 fork。 账号在 13 秒内连续 fork 了 OpenZeppelin Contracts、Foundry、Hardhat、Chainlink、Uniswap v3-core 和 ethers.js。普通访问者会在主页看到熟悉的 Web3 项目名称,但 fork 只表示复制上游仓库,不代表贡献、合作或任何形式的背书。

标题: fig:

版本标记与创建时间不一致。 仓库创建 8 秒后的初始提交同时携带 v2.4.1、v2.4.5、v3.2.3、v3.3.0 和 v3.4.0 五套版本标记,源码头部还声称 2025 年首次发布。这些版本和年龄标记与账号、仓库当日刚创建的公开历史明显不一致。

重复强化社会证明。 “100K+”同时出现在 repository description、 package.json、out/package.json、README badge、README 正文和构建输出中,是项目公开资料中反复强调的用户规模声明。现有材料无法独立验证这一数字的真实性,但这种表述与成熟版本号、企业化 Profile 和知名项目 fork 一样,共同构成了 Solidity Pro 对外展示的成熟产品形象。

标题: fig:

这些宣传内容与前文已确认的实际代码行为形成明显冲突:README 声称不存储 private keys 或 source code,配置把 telemetry 描述为匿名使用数据,构建脚本把 javascript-obfuscator 的混淆过程称为 "privacy"。产品宣称 AI 审计、漏洞扫描和重入检测,但公开命令主要是查询 Gas、显示代币价格和一条通过 Hardhat/Foundry 编译的提示。

组织资料、知名 fork、成熟版本号、100K+、真实可用的小功能和隐私说明均会影响访问者对扩展的初步判断。每个元素单独看都可能正常,异常在于这些信号与恶意代码、快速时间线和旧 publisher 构建残留同时出现。

六、单版本检测的盲区

恶意代码可以删除,但版本历史、发布身份和工程来源不会自动清零。

把前五章的发现放在一起,Solidity Pro 呈现出一种值得平台和安全产品重视的模式:一个已经关联明确恶意历史的扩展名称和 publisher,通过发布未命中原恶意能力的新版本,可以让只检查当前构建的检测重新给出 clean、未命中或低风险的结果。

区分这种模式与正常安全修复,不能只靠新代码是否干净,还需要同时核对四个层面的问题:

  • 哈希与当前 bundle 回答:这个文件现在包含什么。

  • 版本历史回答:这个扩展 ID 或 publisher 此前交付过什么。

  • publisher 和代码来源回答:当前包与哪些已知恶意工程存在直接联系。

  • 当前与历史远程控制面回答:当前本地代码或历史版本是否允许服务器改变交付内容。

对扩展市场和安全产品而言,这意味着检测对象需要从"单个文件哈希"扩展到版本历史、publisher 变化、构建产物差异和远程控制面:

  • 保存历史版本的哈希与解混淆结果;新版本移除大量危险模块时,应触发差异审查,而不是自动恢复信誉。

  • 关联旧 publisher 残留、代码相似度和构建脚本,建立代码或构建产物的来源关联。

  • 将周期 /version 检查、远端 URL 和临时 VSIX 安装记录纳入运行时监控。

  • 将下载量、stars 和企业样式 Profile 仅作为上下文,而不是安全背书。

总结

Solidity Pro 在 helper-beeps 和 web3devtoolsx 两个发布身份下均存在明确恶意实现:2.4.1 以本地随机延迟和环境筛选为前置条件,从远端下载加密 Python 并执行;3.4.0 在 VS Code 启动后自动触发凭据采集,通过 /x 和 /y 两条 HTTP 请求路径外传,同时保留由远端响应驱动的 VSIX 更新通道。初始 3.4.0 的 out/package.json、repository 和版权信息仍指向 helper-beeps,证明两个发布身份的构建产物存在直接来源关联。

GitHub Clean commit 的最终 bundle 移除了这些恶意模块,但仓库仍保留恶意模块源文件;本地重建的 4.0.0 包同样未发现原恶意模块。包含恶意入口和构建物的初始提交到 Clean commit 仅隔 13 分 29 秒,企业样式资料、六个知名 fork、产品仓库和成熟版本声明则在账号创建后约 16 分钟内集中出现。

这个案例最终说明的是:只按当前文件或当前版本判断扩展风险远远不够。恶意代码可以从最新 bundle 中消失,但历史恶意记录不会因此失效——一个干净的新版本,抹不掉同一名称和 publisher 此前交付过恶意代码的事实。

建议

  1. 安装过 helper-beeps.solidity-pro 或 web3devtoolsx.solidity-pro 的开发者应先隔离网络,并保全扩展目录、安装包副本、进程和网络日志,再禁用并卸载相关版本。随后检查 VS Code 进程树、临时目录中的 Python 文件、异常 VSIX 安装记录,以及代理日志中的 /firmware、/x、/y、/version 请求。

  2. 若曾启用运行 Solidity Pro 3.4.0(publisher:web3devtoolsx),钱包私钥、助记词、GitHub/GitLab/npm/PyPI/AWS/Cloudflare/AI 服务及 CI/CD token 可能暴露。应从干净设备优先撤销或轮换相关凭据;加密资产应迁移至使用全新 seed 或私钥的钱包,不能只修改原钱包密码。

  3. 若曾启用运行 Solidity Pro 2.4.1(publisher:helper-beeps),只要主机可能跨过该样本的延迟窗口,或实际运行时长无法确认,就应按潜在本地代码执行事件调查。

  4. 企业安全团队应优先搜索 Extension ID、危险请求路径、已知 Worker、临时文件和异常进程树,再结合两个样本 SHA-256、扩展安装时间与 VS Code 进程网络记录确定受影响范围。重点检测 VS Code Extension Host 启动 detached Python、从临时路径安装 VSIX、读取高价值配置后发起 multipart HTTPS 等行为组合。

  5. 扩展市场应对默认 telemetry 中出现凭据读取、远程下载、解密执行或绕过官方渠道安装 VSIX 的能力进行强制人工审核;保留历史版本并执行跨版本差异审查,避免后续未命中恶意代码的版本自动清除旧版本风险标签。

IOC

恶意文件


filename: helper-beeps.solidity-pro-2.4.1.tar.gz 

SHA256: 7b53b1d93f46babc7415d898e17e71ffb6f3a3af3adb222f21c03adea8b30d50
filename: web3devtoolsx.solidity-pro-3.4.0.gz 

SHA256: bcbaf774f9cea0b0131859b96ba0eeadfd5a49bba59302de1bcf3d884300d508

关于 MistEye

MistEye 是由 SlowMist 自主研发的 Web3 威胁情报与动态安全监控平台,通过 API 提供开源包生态的恶意活动检测与供应链风险预警能力。


本次行动涉及的全部恶意包及 IOC 已接入 MistEye 威胁检测引擎,开发者可通过 API 对项目依赖进行自动化检测,快速判定是否命中已知恶意包并获取处置建议。


📖 API 文档:https://app.misteye.io/api-docs


🛠️ MistEye-DepScan:https://github.com/slowmist/MistEye-DepScan轻量级 CLI 工具,一行命令扫描项目依赖与全局安装包中的已知恶意包,支持 npm / PyPI / Rust(Cargo)/ Go / RubyGems 生态


🛠️ MistEye-Skills:https://github.com/slowmist/misteye-skillsAI 编码助手安全技能包,在依赖安装与 URL 访问前自动触发 MistEye 安全检测


🛠️ MistEye-DNS-Guard:https://github.com/slowmist/MistEye-DNS-GuardRust 实现的本地 DNS relay,检测恶意域名与风险访问,识别钓鱼、C2 等网络威胁。


本文由 SlowMist 威胁情报团队结合 MistEye 威胁情报平台、SlowMist Agent AI 驱动分析编写,有任何问题欢迎咨询反馈。


参考链接:

[1] https://yeethsecurity.com/blog/2026-08-06-Solidity-Pro-WhiteCobra-C2-to-Telegram