Prediction market platform Polymarket temporarily suspended trading after attackers compromised a third-party service integrated into its front end and used it to distribute cryptocurrency-draining JavaScript to visitors. On-chain investigators traced approximately $2.5 million in stolen assets to a suspected attacker-controlled wallet.
This is not a vulnerability in Polymarket's smart contracts or core infrastructure — it is a client-side supply-chain compromise. The attackers poisoned a dependency the platform trusted, and every user who loaded the affected page and interacted with the injected drainer became a potential victim. If your organization operates any web property that loads third-party scripts — analytics, chat widgets, tag managers, ad tech, Web3 connectors — this incident is your threat model made real. If your users or employees hold cryptocurrency wallets and interact with Web3 platforms, they are targets.
The defensive lesson here cuts two ways: platform operators must control what executes in their users' browsers, and end users (including corporate users with wallets on managed endpoints) need detection coverage for drainer behavior and an immediate revocation playbook when exposure occurs.
Technical Analysis
Attack Chain
Based on the reported details, the attack followed the now-standard crypto-drainer playbook:
- Initial compromise (third party): Attackers gained control of a service whose JavaScript was loaded by Polymarket's front end. This could be a compromised CDN asset, a breached SaaS vendor, a hijacked NPM package, or a DNS/account takeover at the vendor — the common thread is that Polymarket's own servers were not breached.
- Payload delivery: The compromised third-party script began serving malicious JavaScript to every browser that loaded the Polymarket site. Because the script came from a trusted, allowlisted origin, it executed with the full privileges of the page context.
- Wallet interaction: The injected drainer presented a fraudulent prompt — typically a fake wallet connection, a malicious
eth_sendTransaction/approve()call, or a spoofed signature request — designed to trick users into signing transactions that transfer assets or grant unlimited token allowances to the attacker. - Exfiltration on-chain: Drained assets were funneled to an attacker wallet, where roughly $2.5M has been traced. Funds are typically moved through swap services and mixers within hours.
Why This Technique Is So Effective
- Trust inheritance: Browser security controls (CSP, SRI, CORS) are frequently absent or misconfigured for third-party marketing/analytics scripts. The malicious code rides in on a domain users and proxies already trust.
- No malware on disk: Drainers run entirely in the browser. Traditional EDR sees a browser process making HTTPS connections — indistinguishable from normal traffic unless you inspect destinations and behavior.
- Signature-based theft: The user authorizes the theft. A single mis-signed
setApprovalForAllor unlimitedapprove()on an ERC-20 token gives the attacker persistent draining capability even after the malicious script is removed. This is why allowance revocation is as critical as blocking the domain.
Affected Products and Platforms
- Primary: Polymarket users who visited the platform during the compromise window and signed wallet transactions.
- Secondary risk population: Any Web3 platform loading un-monitored third-party JavaScript, and any user of browser-based wallets (MetaMask, Rabby, Phantom, WalletConnect flows).
Exploitation Status
- Confirmed active exploitation in the wild with ~$2.5M in confirmed stolen funds traced to a suspected attacker wallet.
- No CVE is associated with this incident — it is a third-party service compromise, not a software vulnerability. There is no CISA KEV entry.
- Drainer-as-a-Service kits (Angel Drainer, Inferno Drainer successors, Pink/Monkey Drainer lineage) are commodity tooling, meaning this exact TTP will be reused against other platforms within days, not months.
Detection & Response
The hard truth: detecting a browser-resident drainer on the endpoint is difficult. The highest-fidelity signals are (1) browsers spawning unexpected child processes or loading injected content from rare domains, (2) network connections to newly registered / known drainer infrastructure, and (3) post-exposure on-chain indicators. The detections below focus on those signals without generating rule-disabling noise.
Sigma Rules
---
title: Browser Process Spawning Script Interpreter or Shell
id: 3f8c2a71-9b4d-4e6f-a1c2-7d5e9f0b1a34
status: experimental
description: Detects browsers spawning cmd, PowerShell, or other script interpreters. Legitimate browsing never requires this — a strong indicator of drive-by exploitation or injected JavaScript escalating to local execution, as seen in crypto-drainer and drive-by campaigns.
references:
- https://www.bleepingcomputer.com/news/security/polymarket-halts-trading-after-crypto-draining-script-breach-25m-traced/
- https://attack.mitre.org/techniques/T1189/
- https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.initial_access
- attack.t1189
- attack.execution
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\chrome.exe'
- '\msedge.exe'
- '\firefox.exe'
- '\brave.exe'
- '\opera.exe'
selection_child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\mshta.exe'
- '\rundll32.exe'
condition: selection_parent and selection_child
falsepositives:
- Rare enterprise browser extensions with native messaging hosts (investigate before excluding)
level: high
---
title: Proxy Connection to Crypto-Drainer Kit Infrastructure Patterns
id: 8a1d4e62-3c7f-4b9a-8e5d-2f6a0c4b7d19
status: experimental
description: Detects proxy/web requests matching URI patterns commonly used by crypto-drainer kits for wallet connection prompts, drainer configuration fetches, and asset theft callbacks. Tune the pattern list against your environment's baseline before production deployment.
references:
- https://www.bleepingcomputer.com/news/security/polymarket-halts-trading-after-crypto-draining-script-breach-25m-traced/
- https://attack.mitre.org/techniques/T1189/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.initial_access
- attack.t1189
- attack.exfiltration
logsource:
category: proxy
detection:
selection_uri:
c-uri|contains:
- '/drain.php'
- '/drainer/'
- 'connect-wallet.php'
- '/wallet-connect/auth'
- 'seaport-verify'
- 'claim-airdrop'
selection_tld:
c-dns|endswith:
- '.top'
- '.xyz'
- '.icu'
- '.click'
condition: selection_uri or (selection_tld and selection_uri)
falsepositives:
- Legitimate Web3 dApp traffic on cheap TLDs — baseline expected dApp domains and exclude known-good
level: medium
KQL — Microsoft Sentinel / Defender
Hunt for endpoints where browser processes communicated with rare, recently-observed domains — the network footprint left when a third-party script pulls drainer payloads from attacker infrastructure instead of the vendor's real CDN. This uses a prevalence-based approach that surfaces low-and-slow connections rather than known-bad IOCs that change hourly.
// Hunt: Browsers connecting to rare domains observed in a short window (drainer payload retrieval)
let Lookback = 7d;
let RareThreshold = 3;
let BrowserProcesses = dynamic(["chrome.exe", "msedge.exe", "firefox.exe", "brave.exe"]);
let RareDomains = DeviceNetworkEvents
| where Timestamp > ago(Lookback)
| where InitiatingProcessFileName in~ (BrowserProcesses)
| where isnotempty(RemoteUrl)
| summarize DomainCount = dcount(DeviceId) by RemoteUrl
| where DomainCount <= RareThreshold;
DeviceNetworkEvents
| where Timestamp > ago(Lookback)
| where InitiatingProcessFileName in~ (BrowserProcesses)
| where RemoteUrl in (RareDomains | project RemoteUrl)
| summarize FirstSeen = min(Timestamp), LastSeen = max(Timestamp),
Connections = count(), Devices = dcount(DeviceId)
by RemoteUrl, RemoteIP, InitiatingProcessFileName
| sort by Connections asc;
// Companion hunt: wallet-related connection prompts from browsers to non-baselined domains
// Run in Defender advanced hunting against web content filtering / network protection events
DeviceNetworkEvents
| where Timestamp > ago(2d)
| where InitiatingProcessFileName in~ (dynamic(["chrome.exe","msedge.exe","firefox.exe"]))
| where RemoteUrl has_any ("walletconnect", "seaport", "blur", "opensea")
and RemoteUrl !has_any ("opensea.io", "walletconnect.com", "walletconnect.org", "blur.io")
| project Timestamp, DeviceName, RemoteUrl, RemoteIP, InitiatingProcessFileName
| sort by Timestamp desc;
Velociraptor VQL
For post-incident scoping on endpoints of users who admit to interacting with the compromised site: enumerate browser persistence surfaces (extensions, injected content caches) and active connections. Drainer-adjacent compromise frequently pairs with malicious extension installs or follow-on infostealer delivery.
-- Hunt: Audit browser extensions and live connections for drainer follow-on activity
-- Run against endpoints whose users visited Polymarket during the compromise window
-- 1. Live network connections held by browser processes
SELECT Pid, Name, Pid as BrowserPid, Address, Port, Status
FROM netstat()
WHERE Name =~ '(?i)chrome|msedge|firefox|brave'
AND Status = 'ESTABLISHED'
-- 2. Chrome/Edge extensions installed outside the enterprise allowlist
-- (drainer campaigns frequently push malicious 'wallet helper' extensions)
SELECT FullPath AS ExtensionPath,
basename(path=dirname(path=FullPath)) AS ExtensionID,
Mtime AS InstallTime
FROM glob(globs='C:/Users/*/AppData/Local/Google/Chrome/User Data/*/Extensions/*/*/manifest.json')
ORDER BY InstallTime DESC
-- 3. Processes spawned by browsers (drive-by escalation indicator)
SELECT Pid, Ppid, Name, CommandLine, CreateTime
FROM pslist()
WHERE Ppid IN (
SELECT Pid FROM pslist()
WHERE Name =~ '(?i)chrome|msedge|firefox|brave'
)
AND Name =~ '(?i)cmd|powershell|pwsh|wscript|cscript|mshta|rundll32'
Endpoint Audit Script
For Windows endpoints belonging to users who may have interacted with the compromised site, this script inventories browser extensions, flags recently modified browser state, and exports active connections for triage.
# Polymarket drainer incident - endpoint triage script
# Run as the affected user (or via your RMM with user-context execution)
$report = @()
# 1. Enumerate Chrome/Edge extensions with recent install/modify times
$extPaths = @(
"$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Extensions",
"$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Extensions"
)
foreach ($base in $extPaths) {
if (Test-Path $base) {
Get-ChildItem $base -Directory | ForEach-Object {
$latest = Get-ChildItem $_.FullName -Directory | Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($latest -and $latest.LastWriteTime -gt (Get-Date).AddDays(-14)) {
$report += [PSCustomObject]@{
Type = 'RecentExtension'
ExtensionID = $_.Name
Browser = ($base -split '\\')[3]
Modified = $latest.LastWriteTime
}
}
}
}
}
# 2. Flag any child processes currently running under browsers
$browsers = Get-Process | Where-Object { $_.Name -match 'chrome|msedge|firefox|brave' }
foreach ($b in $browsers) {
Get-CimInstance Win32_Process -Filter "ParentProcessId = $($b.Id)" |
Where-Object { $_.Name -match 'cmd|powershell|pwsh|wscript|cscript|mshta|rundll32' } |
ForEach-Object {
$report += [PSCustomObject]@{
Type = 'BrowserChildProcess'
ExtensionID = $_.CommandLine
Browser = $b.Name
Modified = $_.CreationDate
}
}
}
# 3. Export for analyst review
$report | Format-Table -AutoSize
$report | Export-Csv "$env:TEMP\drainer_triage_$(Get-Date -Format 'yyyyMMdd_HHmm').csv" -NoTypeInformation
# 4. Flush DNS cache to drop any poisoned resolution of the compromised vendor domain
Clear-DnsClientCache
Write-Host "[+] Triage complete. If extensions or browser child processes were flagged, isolate the host and begin wallet-revocation steps immediately." -ForegroundColor Yellow
Remediation
For Users Who Visited Polymarket During the Compromise Window
- Do not sign any wallet transaction originating from the site until the platform confirms the third-party integration is remediated. Verify through official Polymarket status channels, not links in social media.
- Revoke token allowances immediately. If you connected a wallet or signed anything during the window, assume approvals are compromised. Use revoke.cash or your wallet's built-in approval manager to revoke all ERC-20/ERC-721 approvals granted to unknown spenders — especially unlimited approvals and
setApprovalForAllgrants. This is the single most important step; removing the malicious script does nothing to undo an on-chain approval. - Move remaining assets to a fresh wallet if any suspicious approval or transaction exists on the affected address. Drainers often retain dormant approvals and sweep later.
- Report the theft on-chain. Note the attacker wallet from public tracing (~$2.5M traced) and file reports with Chainabuse and your wallet provider; flagging addresses helps exchanges freeze funds at off-ramps.
- Audit endpoints using the triage script above if the browser session persisted — drainer campaigns routinely upsell victims to infostealer payloads.
For Platform Operators (Any Site Loading Third-Party JavaScript)
- Inventory every third-party script. You cannot protect what you haven't enumerated. Build a complete map of external script origins, including tag-manager-injected resources.
- Deploy Subresource Integrity (SRI) wherever the vendor publishes static assets, and a strict Content Security Policy that allowlists script origins. SRI would have caused browsers to refuse the poisoned script the moment its hash changed.
- Apply least privilege to Web3 connectors. dApps should request the minimum permissions at connection time; never pre-approve blanket allowances, and warn users on any
setApprovalForAllrequest. - Monitor your own supply chain. Continuously scan rendered pages for unexpected script origins and DOM injection (client-side integrity monitoring, e.g., runtime script-diffing). Third-party compromises are invisible to server-side monitoring.
- Have a kill switch. Polymarket's rapid trading suspension limited the blast radius. Define the procedure — and the authority — to pull a compromised integration offline in minutes.
For Security Teams
- Deploy the browser-child-process Sigma rule broadly (low noise, high fidelity) and baseline proxy traffic to cheap TLDs before enabling the drainer-pattern rule.
- Add wallet-drainer social engineering to user awareness: verify URLs, distrust urgent "claim/airdrop" prompts, and treat every signature request as a funds-transfer authorization.
- Ensure your IR retainer covers Web3 incidents — on-chain response (allowance revocation, fund tracing, exchange notifications) has a playbook fundamentally different from traditional breach response.
There is no patch for this class of attack. The controls are architectural: script integrity, origin allowlisting, minimal wallet permissions, and the ability to revoke and respond faster than the attacker can launder.
Related Resources
Security Arsenal Incident Response Services AlertMonitor Platform Book a SOC Assessment incident-response Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.