DEV Community

PandaSecurity
PandaSecurity

Posted on Originally published at panda-security.xyz

Pool Party Snapshot Exploit Drained $215K

Originally published at Pool Party Snapshot Exploit Drained $215K

On 13 November 2026, between 01:34 and 03:38 UTC, an attacker drained 15 liquidity pools run by Pool Party, a self-custodial protocol that lets users invest in AMM positions managed by a pool operator. The project said 12 of the pools were on Arbitrum and 3 were on Base, and that the total loss was approximately $215,000. Pools on Polygon and Robinhood Chain were not affected.

Pool Party's own explanation is short and consistent with what we later checked on Base. Each pool has a snapshot contract that records every investor's position. The attacker found a vulnerability in that contract, changed their recorded position, deposited 10 USDC, and withdrew the pool's funds. The same figures and the same root-cause summary appear in SlowMist's public incident record. The team says a fix is already live on all four chains, and that it has reported the incident to law enforcement and to the exchanges involved.

The official post-mortem and the plan for affected users had not been published at the time of writing. This article sticks to the project's disclosure, SlowMist's confirmation, and on-chain records we verified.

What Happened

Investors deposit into a Pool Party strategy, usually in a stablecoin, and a pool manager runs a Uniswap-style liquidity position on their behalf. Each investor's claim is tracked by a per-pool snapshot contract, which stores recorded liquidity, accumulated fees and share data, and exposes a syncInvestor function that updates the record against later pool-wide snapshots.

Withdrawals are supposed to pay an investor according to that record. That design is reasonable only if the record cannot get ahead of the assets the investor actually contributed. In this incident, it did.

The attacker used the externally owned account 0x2075c17abbd077cf6406736bb7047ed446ab7f8f, which Pool Party published in its incident thread. On Base, that address called the protocol's Position Manager at 0xd6f2f4b4638f8783e2b7697454c6bf292f25b54f — the same contract published on Pool Party's security page — and called syncInvestor on the snapshot contracts attached to individual pools. The pattern matches the team's description: a 10 USDC addLiquidity call, snapshot syncs, and then a withdraw that returned far more than the deposit.

Timeline

  • 13 November, 01:34–03:38 UTC: the attacker drains 15 pools (12 on Arbitrum, 3 on Base), according to Pool Party.
  • 13 November, 01:59 UTC onward on Base: we see the first of several 10 USDC deposits into the official Position Manager, followed by syncInvestor calls and oversized withdrawals. Activity on Base continues through about 03:34 UTC.
  • 13 November, 04:58 UTC: Pool Party later said 115,056.36 DAI, paid with funds from this incident, arrived at 0xd40b1c59f3f0f17203cb443fddd6b92c4734233b from CCE Cash.
  • 13 November, 18:13 UTC: the team sent an on-chain message on Arbitrum offering a 10% white-hat bounty if the remaining approximately $193,500 was returned to 0x524d0A20EDFD36adD3a5eF5f5939958dF098B149.
  • 13 November, 18:23 UTC: Pool Party published the public incident thread, confirmed the $215k figure, named the attacker address, said the funds had already been converted to XMR, and stated that the snapshot-contract fix was live on Arbitrum, Base, Polygon and Robinhood Chain. The team thanked pcaversaccio and SEAL 911 for help during the incident.

What the Base Transactions Show

A complete per-pool loss table for all 15 pools is still pending, and public Arbitrum explorer pages were not reliably available to us at the time of writing. We could, however, pull receipts for the attacker's Position Manager transactions on Base from a public RPC.

Those receipts confirm the "deposit 10 USDC, then withdraw the pool" part of the official story. In the Base window, the attacker made seven addLiquidity calls, and each one transferred exactly 10 USDC from the attacker to the Position Manager. One of the first is 0xdd45e871…62ea71, included at 01:59:52 UTC.

The withdrawals are a different scale. In 0xead5f187…5fc14a, at 03:14:01 UTC, the attacker received about 4,265 USDC. In 0x23788769…42fee7, about three minutes later, they received another 4,140.52 USDC. A later withdrawal, 0xdaf0544a…016b8 at 03:26:18 UTC, paid them about 3,621 USDC.

Adding up the Base Position Manager transactions we decoded, the attacker received about 12,066 USDC and spent 70 USDC on those seven deposits, for a net of about 11,996 USDC on Base. That is a minority of the official total, as expected if most of the drained pools were on Arbitrum. We keep approximately $215,000 as the loss figure because that is the number Pool Party published and SlowMist recorded.

On Base, the syncInvestor calls went to per-pool snapshot contracts, including:

  • 0x01ac4dfcc81db3cb775196a569aaddff1dff8797
  • 0x8bdcb2e8169f3a339bce815643ca84505c5c9506
  • 0xd5741416006a0f736757ff7c5109cda9165826a0

Those three contracts line up with the project's claim that three Base pools were hit.

Why a Snapshot Record Is a Dangerous Source of Truth

Verified source for the protocol's snapshot library and Position Manager is public on Sourcify. At a high level, the snapshot contract keeps two kinds of state: a pool-wide position snapshot (liquidity and fee indexes for the whole strategy) and a per-investor snapshot (that investor's recorded liquidity, fees and share percentages). syncInvestor is meant to bring an investor's record forward so that later withdrawals can be settled against the latest pool state.

The snippet below is a simplified sketch of the trust boundary, not the deployed code and not a reproduction of the bug:

// Simplified for illustration
function withdraw(address investor) external {
    InvestorState memory rec = snapshots[investor]; // recorded position
    require(rec.liquidity > 0, "no position");

    uint256 share = rec.liquidity;                  // trusted record
    uint256 assets = poolAssets() * share / total;  // paid from the pool
    snapshots[investor].liquidity = 0;
    stablecoin.transfer(investor, assets);
}
Enter fullscreen mode Exit fullscreen mode

If rec.liquidity can be increased without a matching deposit of assets, a later withdraw pays the attacker out of everyone else's pool. That is the same family of failure we described in the Arcus Perps subaccount accounting exploit: an internal balance was allowed to grow, and a withdrawal function believed the book. It is also close to the ACryptoS depositMulti vault exploit, where a small deposit minted an outsized share of the vault.

Pool Party has not yet published a line-by-line post-mortem, so we will not pretend to have isolated a single arithmetic step as the bug. What is already clear, from the team's own wording and from the Base receipts, is the trust model: the snapshot was treated as the investor's claim, and that claim became detachable from the 10 USDC the attacker actually put in.

Aftermath

Pool Party says the vulnerability in the snapshot contract has been corrected on all four chains, including the two that were not drained. The public thread also says the attacker had already converted the funds to XMR by the time the announcement went out, and that the team is tracking the funds with security researchers. They asked zachxbt and other investigators to get in touch, and they pointed users to Discord for live updates.

The white-hat offer — keep 10%, return the rest to 0x524d0A20EDFD36adD3a5eF5f5939958dF098B149, and the team would not take legal action — was posted on-chain in 0x991c1766…95f950 at 18:13:22 UTC. We have not seen a public confirmation that the funds were returned. A later message, relayed by Defimon Alerts, asked the DAI-receiving wallet's owner to contact security@pool-party.xyz if the payment arrived in a normal trade, and restated the same bounty.

Whether affected investors will be made whole is a question for the promised post-mortem and reimbursement plan. This article is technical commentary, not financial advice.

Lessons for Builders

Do not let a derived ledger become a source of funds. Snapshot, share and index accounting exists to make withdrawals cheap and to attribute fees correctly. The assets in the pool, or an invariant that those assets still cover every recorded claim, have to remain the final check. If a recorded position can be updated in isolation, a withdraw function becomes a printer.

Treat "sync" functions as security-critical. A permissionless function that rewrites an investor's liquidity or share percentage is part of the value path, even if it never moves tokens by itself. Invariant tests should assert that no sequence of syncs, deposits and withdrawals can increase an investor's claim except by the value actually paid in, net of fees.

A minimum deposit is not a security control. Requiring 10 USDC, or any other small floor, does not protect a pool whose accounting can mint a much larger recorded position. The deposit may only be there to satisfy a "has a position" or "non-zero contribution" check.

Ship the same fix everywhere the code is deployed. Pool Party's Polygon and Robinhood Chain pools were not drained, but the team still patched all four chains the same day. That is the right move when the same snapshot design is shared across deployments.

Have a reachable contact path before you need it. The team published a clear attacker address, a bounty address and a security email, and it worked with SEAL 911 during the event. Those are operational controls, not substitutes for the accounting invariant.

What Users Should Know

If you had funds in a Pool Party pool on Arbitrum or Base during that window, follow the team's updates on the official X account and Discord rather than any unsolicited "recovery" message. The official security page is pool-party.xyz/security, and the team has said it will publish a full post-mortem and a plan for affected users.

If you use similar vault or managed-LP products elsewhere, remember that self-custody of the wallet does not remove smart contract risk. Prefer products that can show a published audit of the exact contracts you are depositing into, and be cautious when a protocol's security page still lists a missing audit, as Pool Party's own page did around this period.

Sources

Closing Thoughts

The Pool Party loss is a reminder that a pool's books can be as dangerous as its token transfers. Once a withdrawal function trusts a recorded share, any bug that inflates that share spends other users' funds, no matter how small the attacker's own deposit is. If you are building a vault, a managed LP product or any design that snapshots investor positions, talk to our team or check our audit pricing to have that accounting path reviewed before a live withdrawal is the first test.

Top comments (0)