TL;DR
On October 29, 2026, Polymarket put its international exchange into cancel-only mode and paused its relayer after traders reported funds leaving their accounts. A wallet flagged as the attacker's held about $2.65 million in POL, per Arkham data reported by The Block, after a run of USDC.e-to-POL swaps through Relay. Polymarket said only that "one of our third party providers was compromised." Hudson Rock pulled the culprit file from DebugBear, a website performance-monitoring vendor whose real user monitoring (RUM) script ran on Polymarket.com: 15,187 bytes of JavaScript that found the logged-in trader's own trading client, sold or transferred their positions, and pushed signed batches through Polymarket's own relayer to a hard-coded fallback wallet. That $2.65 million is a balance snapshot of the attacker's wallet; nobody has published a victim-by-victim loss accounting. No contract bug was involved, and Hudson Rock found no code that steals keys. Polymarket says it is fully reimbursing affected traders. This was its second frontend vendor compromise since June. On a page that can sign, every third-party script is a signer.
What Happened at Polymarket on October 29?
Polymarket froze trading for about an hour. BleepingComputer's timeline has the exchange in cancel-only mode with relayer actions paused at 2:05 p.m. ET (18:05 UTC), a "fixed" notice at 2:37 p.m., and the incident marked resolved at 3:05 p.m. ET.
The company has said little beyond that. It referred the case to law enforcement, promised that "anyone who has been impacted will be made whole," said after trading resumed that it is "fully reimbursing all affected traders," and has kept the provider's name, the victim count and the loss to itself. A person familiar with the matter told CNBC the provider was DebugBear, a U.K. performance-monitoring company, and that Polymarket's U.S. platform was not affected, as RG.org summarizes. DebugBear posted that it was "impacted by an ongoing security incident" and asked RUM customers to remove its embed code from their sites.
Two pieces of hard evidence tie the two companies together. Hudson Rock downloaded cdn.debugbear[.]com/C7xcKKrjUnXK.js twice at 18:12 and 18:13 UTC and got byte-identical wallet-draining code both times. And Polymarket's own production bundle carried build metadata reading chore(polymarket): remove debugbear rum script (#15337), timestamped 17:59:20 UTC, six minutes before the public freeze.
How Much Was Actually Stolen?
About $2.65 million is the best headline figure, and it is an estimate. No party has published a victim-by-victim accounting.
| Figure | Who | What it measures |
|---|---|---|
| ~$2.65M in POL | Arkham, via The Block and Decrypt | Attacker wallet balance after the Relay swaps |
| BleepingComputer | POL the wallet sent onward to three addresses | |
| ~$2.19M | Hudson Rock | A PolygonScan balance screenshot, capture time unknown |
| ~$2.7M, ~700 users | Bubblemaps, via WIRED (RG.org) | Analyst estimate of losses and victims |
| ≥$2.7M, 710 wallets | Betting Intelligence and Polysights, via CNBC (RG.org) | Withdrawals traced to one account |
Most of the spread is price. The wallet's proceeds sat in POL, a volatile asset, and each snapshot was taken at a different moment. The on-chain quantity is the stable number: one transfer alone moved 18,613,584 POL out of the wallet at 18:28 UTC, and RG.org's read of Polygonscan puts the three outbound transfers at about 28.6 million POL between 2:28 and 2:38 p.m. ET. BleepingComputer valued that count at about $2.57 million, within 3% of Arkham's $2.65 million, so we use $2.65 million as the headline and 28.6 million POL as the hard number.
The Block's "within minutes" undersells the window. By our read of the wallet's history on Blockscout, its POL balance passed 16.4 million by 17:49 UTC and reached about 28.57 million by 18:03 UTC, with only small amounts arriving after that. The earliest transfer into the address we can find is an ERC-1155 batch of Polymarket outcome tokens at 17:26:29 UTC, which matches the script's external-wallet branch. Inflows ran from 17:26 to about 18:03, roughly 37 minutes. Polymarket's removal build is stamped 17:59, so its team was already reacting while transfers were still landing, and the exchange froze at 18:05.
How Did a Performance Script Drain Wallets?
A RUM script is JavaScript a site embeds so a vendor can measure how fast real visitors' pages load. It runs inside the page, with the page's full privileges, and phones home with metrics.
Hudson Rock's static analysis of the captured file shows what the hijacked version did with those privileges.
- Read the session. It pulled three localStorage entries,
polymarket.auth.params,polymarket.auth.proxyWalletandpoly_clob_api_key_map, to learn the account type, the trader's deposit wallet and their order-book API credentials. - Find the trading desk. It walked React's internal component tree until it found an object exposing
postOrderandcreateOrderorcreateMarketOrder, then used that object and its signer. This is code written against Polymarket's frontend specifically. - Pick targets. It priced balances and positions against fallback thresholds of 10 for the whole portfolio and 10 per position (Hudson Rock does not state the unit), and quit for visitors Polymarket's own geoblock check refused.
- Take the assets. The path depended on how the trader logged in (see below).
- Report back. It posted wallet address, IP, country, account type, portfolio value and transfer results to
data.debugbear[.]comunder/metrics/paths.
Hudson Rock found no routine that exfiltrates passwords, seed phrases or private keys. The trader was already logged in, and the script borrowed the authority the page already held.
For traders on an external wallet, the code built an ERC-1155 batch transfer of their outcome tokens straight to the recipient. For email-login accounts, it placed sell orders "at increasingly aggressive prices" and then moved the proceeds. The cash leg was an EIP-712 DepositWallet batch, signed by the user's own signer and submitted to Polymarket's own relayer, with a swap route to the recipient and a plain token-transfer fallback.
Hudson Rock did not run the sample and notes that a signing request does not prove a silent signature. The on-chain result is not in doubt.
The Attack, Step by Step
| Step | What happened | Evidence |
|---|---|---|
| 1 | DebugBear's CDN serves a 15,187-byte drainer at the RUM script URL Polymarket embeds | Hudson Rock capture, SHA-256 0755e767...79e5 |
| 2 | Script reads the logged-in session from localStorage and locates the trading client in React | Hudson Rock static analysis |
| 3 | Positions are transferred or sold; proceeds are batched through Polymarket's relayer | Hudson Rock; Decrypt on relayer role |
| 4 | Attacker wallet receives outcome tokens and swaps proceeds from USDC.e to POL through Relay | The Block (Arkham); wallet history |
| 5 | The attacker wallet makes its own outgoing safeTransferFrom calls on Polymarket's Conditional Tokens contract, 17:50 to 17:56 UTC (1:50 to 1:56 p.m. ET), moving outcome tokens it received onward | BleepingComputer; method names on Polygonscan |
| 6 | Polymarket build removes the DebugBear script, 17:59:20 UTC | Polymarket bundle metadata, via Hudson Rock |
| 7 | Exchange to cancel-only, relayer paused, 18:05 UTC | BleepingComputer |
| 8 | After sitting on the POL for about 23 minutes past the freeze, the wallet sends about 28.6M POL out in three transfers, 18:28 to 18:38 UTC | Polygonscan, RG.org |
| 9 | Trading resumes; Polymarket promises full reimbursement | The Block |
The removal build at 17:59 did not end the drain on its own. Pulling a script from the next deploy does nothing to a tab that already loaded the old one, and Hudson Rock flags exactly this: a build time "does not establish the exact exposure window." By our read of the wallet's token-transfer history, outcome-token and USDC.e transfers kept arriving through 18:02 UTC, including this outcome-token batch at 18:02:17, before inflows levelled off around 18:03.
The relayer pause at 18:05 is the control that reaches every open tab. The same component the attacker used as a delivery rail was the operator's kill switch: Polymarket runs its relayer, so pausing it stops every relayed batch at once, whichever tabs still hold the old script. Inflows had levelled off by 18:03, so we cannot say the pause stopped transfers in flight. It guaranteed that those tabs could relay nothing new. External-wallet transfers may have bypassed the relayer anyway. The three addresses that received the 28.6 million POL have no public tracing that we could find as of October 30.
Why Did This Happen Twice in Four Months?
Both attacks came through the same door: third-party code allowed to run on the signing page. On June 25, Polymarket said a third-party vendor had been compromised and was "injecting a malicious script into our frontend for some users." Source Defense's teardown of that incident traced it to a marketing tag that loaded a second library from another host. The legitimate library weighed about 479 KB. The version served during the attack was an 18 KB drainer that prompted for an EIP-712 authorization until victims approved and then submitted it through Polymarket's gasless relayer. It took about $3 million from roughly 11 wallets. Decrypt adds a third 2026 incident: a private key compromise in May that drained about $700,000 from an internal top-up wallet.
| June 25 | October 29 | |
|---|---|---|
| Delivery | Nested library behind a marketing tag | DebugBear RUM script on its own CDN |
| Victim floor | MIN_USD: 100000 | Thresholds of 10, unit unstated |
| Victims (analyst estimates) | About 11 wallets (Source Defense) | About 700 users (Bubblemaps) |
| Take | About $3M | About $2.65M |
| Average per victim (our arithmetic on those estimates) | About $270,000 | Under $4,000 |
The June operator hunted whales and stayed quiet. Source Defense notes the high floor "dramatically reduced the number of victims while allowing the campaign to remain active longer." The October operator dropped the floor to almost nothing and ran a dragnet across hundreds of accounts in under 40 minutes. Both approaches cleared seven figures.
(We have no evidence that the same actor ran both. Polymarket never named the June vendor, and nothing published links it to DebugBear.)
Why Didn't CSP, SRI or a Vendor Review Stop It?
Content Security Policy is an allowlist of origins. Polymarket allowed cdn.debugbear.com because it chose to run DebugBear, and the script's reports went to DebugBear's own data host, the same place a RUM script sends metrics anyway. When the file at an allowed origin turns hostile, CSP runs it. Source Defense says Polymarket already ran "a sophisticated and well-managed Content Security Policy" in June. It made no difference then either.
Subresource Integrity pins a script to a hash, so the browser refuses changed bytes. It works for a file that never changes. A vendor-hosted snippet that the vendor updates in place cannot be pinned without breaking it every time the vendor ships, which is why so few sites pin analytics.
A vendor review would have passed too. DebugBear is a legitimate tool. How its infrastructure was breached is still unknown: Hudson Rock lists the initial compromise as unresolved, and notes that the CDN's Last-Modified header read October 27, 2026, a date it declines to treat as the start of the attack. So do we. Whoever controls that file controls code inside a logged-in trading page.
This is CWE-829, inclusion of functionality from an untrusted control sphere, and crypto has paid for it before. In December 2023 a poisoned release of Ledger's Connect Kit library injected a drainer into every dApp that loaded it and took roughly $600,000 in a few hours, as cside recounts in its own Polymarket write-up. We covered the same class in the Injective SDK npm backdoor. Here, on an email-login account the signer lives inside the page, so the script may not have needed a victim to approve anything at all (Hudson Rock did not test this, and wallets differ).
Why This Matters Beyond Polymarket
Embedded wallets and gasless relayers removed a confirmation step that used to sit between a script and a user's funds.
A classic dApp asks an external wallet to confirm each transaction, and a hostile script has to get a human to click. An email-login account with an in-page signer and a gasless relayer can, depending on the wallet, trade and settle from the page with little or no prompting. That also means any JavaScript that runs on the page inherits the trader's full authority, and the Fomo bookmarklet theft earlier this month showed the same property from a different direction.
An audit certifies the contracts you showed it. Polymarket's contracts did exactly what properly signed messages told them to do. The failure sat in the browser, inside a monitoring tag that could place orders as the user.
What Should Operators Do?
- Inventory every script on pages that can sign. Include what tag managers and vendor loaders pull in at runtime. June's drainer sat two hops away from Polymarket's own code.
- Take non-essential third parties off signing origins. Performance monitoring, analytics and marketing tags do not need to run where a session key lives. Put signing and trading on an origin or frame that loads first-party code only.
- Self-host and pin what must stay. Copy vendor snippets into your own build so a vendor's CDN cannot change them under you, then use SRI on anything you still load remotely.
- Narrow what page code can reach. Do not leave a live trading client and signer reachable from global state or a React tree any script can walk. Require a fresh user action for transfers out of the deposit wallet.
- Watch your own relayer and token contract. Both legs of this attack left first-party traces. Email-login accounts paid out through DepositWallet batches on Polymarket's relayer, and external-wallet accounts sent outcome tokens through Polymarket's own Conditional Tokens contract. Both converged on one address nobody had seen before. An outside monitor cannot see a relayer's queue, so this rule belongs in the operator's own stack: fire when ten distinct accounts send to the same new address. By our count of the wallet's token-transfer history, the tenth distinct sender arrived at 17:33:28 UTC, seven minutes after the first, 26 minutes before the 17:59 removal build and 32 before the 18:05 freeze. Most of the value arrived after that: the wallet's POL balance passed 16.4 million by 17:49 and reached about 28.57 million by 18:03.
- Rehearse the kill switch. A script removal only protects new page loads. Know which control halts signed activity for every open tab, who can trigger it, and how long it takes.
An audit would not have stopped the CDN swap itself, and the live signals in item 5 sit in an operator's own relayer and token contract. What an audit changes is how much a swap can reach, by finding the precondition that made this one worth $2.65 million: third-party code on the signing page, with reach to the session, the order client and the signer. Our dApp security audits cover frontend supply chain risk from injected scripts and CDN hijacking, malicious transaction construction, and wallet integration and signing flows. We map every third party that can reach your signer, trace the path a hostile script would take to it, and test whether your relayer would carry a transfer to an address the user never chose.
Frequently Asked Questions
Were Polymarket's smart contracts hacked?
No. The contracts processed transfers and orders that were signed through the traders' own sessions. The malicious code ran in the browser, loaded from DebugBear's CDN, and used Polymarket's own trading client and relayer to move funds, according to Hudson Rock's analysis.
Which third-party provider was compromised?
DebugBear, according to a source who spoke to CNBC. Polymarket has not named the provider publicly. DebugBear confirmed an ongoing security incident and told RUM customers to remove its embed code, and Polymarket's production build records the removal of the DebugBear RUM script.
How much did Polymarket users lose?
About $2.65 million is the best estimate, and it is a snapshot of the attacker wallet's balance, per Arkham, since no victim-by-victim accounting exists. The wallet sent about 28.6 million POL onward, and estimates from $2.19 million to $2.7 million mostly reflect the POL price at different moments. Bubblemaps estimates about 700 affected users; Polymarket has published neither figure.
Would a Content Security Policy have prevented this?
No. CSP decides which origins may run code, and DebugBear's CDN was an allowed origin by design. Removing third-party scripts from signing pages, or self-hosting and pinning them, addresses this class.
Sources / References
- The Block: Polymarket resumes trading after $2.65 million exploit, says third-party provider was compromised
- Hudson Rock (InfoStealers): Polymarket Breach Alert: Wallet-Draining Code Found in a Third-Party Script
- BleepingComputer: Polymarket halts trading after crypto-draining script breach, $2.5M traced
- Decrypt: Polymarket Pauses Trading as Prediction Market Investigates Security Incident
- RG.org: Polymarket Pauses Trading After Third-Party Provider Breach
- Polygonscan: 18,613,584 POL transfer from the attacker wallet
- Polygonscan: first outcome-token batch into the attacker wallet, 17:26:29 UTC
- Polygonscan: outcome-token batch into the attacker wallet after the removal build, 18:02:17 UTC
- Blockscout: attacker wallet POL balance history
- Source Defense: Polymarket Users Drained of $3M by a Trusted Third-Party Script Exposing the Limits of CSP and SRI
- cside: Inside the Polymarket $3M client-side supply-chain attack
- MDN: Subresource Integrity
- MITRE: CWE-829, Inclusion of Functionality from Untrusted Control Sphere



