Polymarket drained through a hijacked DebugBear script
A tampered performance-monitoring script on Polymarket sold traders' positions and moved over $2 million. How it worked and how to audit your own third-party scripts.
By Yaali. October 31, 2026, 6 min read, Supply chain, Threat intel, Web apps.
On October 29, traders on Polymarket's international site watched their positions sell and their balances leave without touching anything. The cause was a JavaScript file loaded from DebugBear, a web performance monitoring service the site used to measure page speed for real visitors. Someone replaced that file with code that searched each logged-in session for the user's trading client and used it to move funds. Polymarket froze trading, restored it the same evening, and said that "anyone who has been impacted will be made whole."
Polymarket has not published a loss figure. On-chain analysts put it between about $2.5 million (traced to the attacker's wallet, per BleepingComputer) and $2.71 million from roughly 700 deposit wallets (per GoPlus). Polymarket's CFTC-regulated US exchange was not affected. The lesson reaches far beyond prediction markets: any site that loads a vendor script from the vendor's own server gives that vendor's infrastructure the same power in the browser as its own code.

How the attack worked
Real user monitoring (RUM) products work by having the customer paste a one-line script tag into every page. The tag points at a file on the vendor's content delivery network, here cdn.debugbear.com/C7xcKKrjUnXK.js, a per-project file. Because the browser runs it in the page's own origin, it can read everything the page can: the DOM, cookies not marked HttpOnly, and local storage.
Hudson Rock pulled the file that was being served and found a 15,187-byte drainer in place of the monitoring code (SHA-256 0755e767504d8103f6c27b9e765a1026507a17c04513242adb503df7777879e5). It read three local storage entries: polymarket.auth.params, which holds the login type and wallet address; polymarket.auth.proxyWallet, the deposit wallet that holds the funds; and poly_clob_api_key_map, the user's API credentials for Polymarket's order book (the CLOB, or central limit order book).
The script then walked the running React application to find the object that already places orders for the user, along with its signer. Nothing in Polymarket's smart contracts was exploited. The drainer used trading permissions the victim's own browser already held, so every request it sent looked like the user acting.
What happened next depended on the account type:
- Accounts connected with an external wallet (EOA, an externally owned account) got a batch transfer of their position tokens straight to the recipient address.
- Accounts created with email login through Magic received sell orders at progressively worse prices, and the script then tried to move the proceeds out.
In both cases the script built EIP-712 signed messages (the Ethereum standard for structured, human-readable signatures) for Polymarket's deposit wallets on Polygon and submitted them to Polymarket's own relayer. It reported each victim's wallet address, IP-based location and portfolio value back to data.debugbear.com under the paths /metrics/submit, /metrics/update and /metrics/handle, so the exfiltration traffic went to a domain the site already trusted.
What attackers did and what is still unknown
The drained funds were swapped to POL, Polygon's native token, and collected at 0x3F99139F1C5854bb628c2e576Aaf638e99dFfc18, the default recipient written into the script. Hudson Rock notes the script could fetch a different recipient from a remote configuration, so treat that address as the known collection point rather than a complete map of the theft.
Polymarket's production build carries the commit message "chore(polymarket): remove debugbear rum script (#15337)" with a build timestamp of 17:59:20 UTC. DebugBear posted on X that it was "impacted by an ongoing security incident" and told every RUM customer to remove its embed code. Polymarket said one of its third-party providers was compromised and that it had referred the case to law enforcement. Trading was back online by about 19:00 UTC.

Three things are not public yet. DebugBear has not said how the attacker gained control of the file, how long it was served, or whether other customers received tampered code. The recovered sample only reads Polymarket's storage keys and calls Polymarket's APIs, so it was written for this one target. This is also Polymarket's second vendor-script incident this year: on June 25, a different compromised vendor injected a drainer that took about $3 million from fewer than 15 accounts.
What to do
If you use DebugBear RUM, remove the embed snippet from every template, tag manager container and single-page app bundle now, as DebugBear instructed. Search your code and your tag manager for debugbear.com. Then pull your web server or CDN logs and your Content Security Policy (CSP) violation reports for requests to cdn.debugbear.com and data.debugbear.com since October 27, the date on the tampered file, to see which pages loaded it.
If you traded on Polymarket on October 29, close any tab left open from that day, since a page already loaded may still hold the old script. Check your order and transfer history for sells and transfers you did not make, and look on Polygonscan for transfers to the recipient address above. Revoke and recreate your CLOB API keys, save the transaction hashes for the reimbursement process, and ignore any "recovery service" that contacts you first.
For any site that loads third-party JavaScript, start with an inventory. List every external script on your sensitive pages (login, checkout, account, trading), who owns it and why it is there. Scripts nobody can justify should go.
For the ones that stay, pick the control that fits:
- Self-host a pinned copy and update it on purpose, so a change on the vendor's server cannot reach your users.
- Where the vendor publishes versioned files, add Subresource Integrity (SRI): an
integrity="sha384-..."attribute that makes the browser refuse a file whose hash has changed. Per-project files that the vendor rewrites, like most RUM and tag scripts, cannot take SRI, which is a reason to self-host them. - Keep monitoring and analytics off the pages that hold credentials or sign transactions, or run them in a sandboxed iframe on a separate origin so they cannot read your storage.
- Set a strict CSP with
script-srcandconnect-srcallowlists and areport-toendpoint, and alert on new script hashes or new destinations. CSP alone would not have stopped this attack, because the attacker used a domain already on the list.
Finally, take long-lived secrets out of local storage. Any script on the page can read localStorage. Session material held in HttpOnly cookies, plus a confirmation step for transfers that a script cannot click through on its own, would have left this drainer with far less to work with.
The wider lesson
A monitoring tag gets added by one team, approved once, and then forgotten, while the file behind it can change on any deploy the vendor makes. Treat a third-party script with the same suspicion as a dependency in your build: know its owner, pin its version where you can, and watch it for changes. For financial and identity pages, assume any external script is code an attacker may one day control.
Reviewing what third-party code runs on your sensitive pages, and whether a tampered file could reach session data, is part of our web penetration testing and attack surface management work. If you want to know what would happen if one of your vendors' scripts turned hostile, open the chat and Yaali, our AI agent, will pass your question to an engineer.
Sources: Hudson Rock / Infostealers.com, BleepingComputer, CoinDesk, Cyber Kendra, ohey.ca research, DebugBear on X, SC Media, KuCoin News (GoPlus figures).
Read next
- UK police data keeps leaking through suppliers
- Convertr's own analytics script skimmed checkout cards
- Gheist: stolen GitHub tokens dump secrets into Actions logs
Back to the blog, or tell us about your system in the chat. Yaali, our AI agent, answers first and brings in an engineer.