October 20, 2026
|
Exploit Postmortem
Cover image for "Crypto DAO's $52K Loss and How Olympix Would Have Prevented It"

Crypto DAO's $52K Loss and How Olympix Would Have Prevented It

Date: July 28, 2026

Chain: BNB Chain

Loss: about $52K in attacker profit, per GoPlus, from 167,200 Pro sold out of the exploited contract

Class: a public exec() function with no check on who calls it

At 17:13:39 UTC on July 28, 2026, an operator account that had already sent close to seven thousand transactions on BNB Chain upgraded the proxy at 0xc44f...4A3C to a new implementation. According to GoPlus, the only change that mattered was a check on the caller's address, added to a function called exec(). About an hour and a half earlier, someone had called that function 305 times in a single transaction.

The contract belongs to the Pro token of Crypto DAO, a BNB Chain project whose ecosystem also includes a CDAO token. GoPlus counted 167,200 Pro sold out of it during the attack and about $52,000 of profit for the attacker. The Crypto Times reported the incident as an $8.2M drain, and a DeFiHackLabs proof of concept describes it the same way, but the chain shows that money landing in Crypto DAO's own receiver wallets and moving on to a contract owned by the account that administers the exploited contract.

A Seller Meant to Run on a Schedule

The exploited contract holds Pro and sells it into the Pro/USDT PancakeSwap pair in small, fixed amounts. Each exec() call in the attack moved 50 Pro out of the contract, 1.25 to a fee address and 48.75 into the pair, and the USDT that came back went to one of three receiver addresses in rotation. GoPlus's analysis says those receivers are addresses specified by the exploited contract, not the attacker's, and the contract's storage confirms it: a three-address receiver list held exactly those three wallets at block 100,000,000 on May 23, 2026, more than two months before the attack, when the attacker's address hadn't yet sent a single transaction. The list was still unchanged in the block before the attack, and it holds a different three addresses today.

The account that upgraded the proxy, 0xe561...4a59, owns the ProxyAdmin that controls it and had sent 6,896 transactions by October 2026, against the attacker's 15. Each sale of 50 Pro moves the price only slightly when it happens at a pace the operator chooses.

When Anyone Can Press Sell

exec() had no access control. GoPlus's root cause is one sentence: the function lacked access control and could be called by any contract. Once anyone can call a selling routine, they also control its timing and its frequency, and a seller that's harmless at one call per interval becomes a lever on the pool price when it's called hundreds of times inside a trade someone else has set up.

Access control on a treasury function protects more than the funds it moves directly, because it also protects the market around those funds from a caller who can choose exactly when the sales happen. A shop that lets any customer ring up its clearance markdowns can lose money without anyone touching the till.

305 Calls in One Transaction

GoPlus lists the attacker as 0x4276...F45D and the attack contract as 0xf00b...50ac, and gives 0x6a50...0ff4 as an example attack transaction. That transaction ran at 15:44:54 UTC in block 112652246, and its token transfers show the sequence.

The attack contract took 68,381.24 Pro out of the Pro/CDAO pair as a flash swap, a loan of the pair's own tokens that has to be settled before the transaction ends. After a 1,709.53 Pro transfer to the same fee address, it sold 66,671.71 Pro into the Pro/USDT pair for 3,681,405.54 USDT, which pushed the Pro price down. Then it called exec() 305 times. Each call sold another 50 Pro from the exploited contract into the already depressed pair, for 15,250 Pro in total, and sent the USDT to the three receivers, starting near 2,464 USDT per call and falling to about 2,374 by the end as the price kept sliding.

Finally, the attack contract spent 3,667,960.26 USDT buying Pro back at the lower price, sent 68,552.62 Pro to the Pro/CDAO pair to settle the flash swap, and passed 13,445.27 USDT to the attacker's address. A reply under GoPlus's thread described the same shape as a reverse sandwich: sell first, let the forced sales push the price further, then buy back cheaper. The attacker's address made 15 transactions in total, and GoPlus puts the profit across the attack at about $52K.

Where the $8.2M Actually Went

The 17:13 UTC upgrade replaced the implementation behind 0xc44f...4A3C with 0xF912...0059, which GoPlus says adds a check on the caller's address. As of October 20, 2026, Crypto DAO's X account hadn't posted about the incident, and The Crypto Times reported that the team hadn't acknowledged it or published a post-mortem when it wrote its story.

The $8.2M figure and the $52K figure describe different flows of money. In the example transaction alone, the three receivers took in roughly 737,000 USDT while the attacker's address received 13,445, and The Crypto Times and the DeFiHackLabs proof of concept counted the receivers' total intake as the attacker's take. Neither the attack transaction's input nor the attack contract's code contains the receivers' addresses, though, and the exploited contract read them from its own stored list, which had held the same three addresses since at least May 23.

What the receivers did next settles whose wallets they are. Between 16:59:50 and 17:01:17 UTC on July 28, a few minutes before the patch went in, they sent 2.6M, 2.6M and 2.4M USDT to 0xc2d8...9a13, a contract whose owner is 0xe561...4a59, the same account that owns the ProxyAdmin and pushed the fix. On August 4 and 5, the other two receivers moved their remaining USDT into the first, which sent a further 1,000,000 USDT to the same contract on August 5. The forced sales converted Crypto DAO's own Pro into USDT for Crypto DAO, at prices the attacker had pushed down, and the value that actually left the project's control was the attacker's profit, which GoPlus puts at about $52K.

How Olympix Finds a Selling Routine Anyone Can Trigger

Olympix reads a contract the way an attacker does, as a set of states, transitions and entry points, and it takes in the context around the code, including which addresses are meant to operate it and which pools it trades against, to infer the invariants the system depends on. In this contract, the state that matters is the treasury's Pro balance and the price it sells at, and the entry point that changes both is exec().

Olympix's static analysis surfaces the signal directly: a public, state-changing function that moves treasury tokens into a pool and has no restriction on its caller. Olympix has flagged this class before in other codebases. From that signal, the engine narrows from every path, to the feasible ones that reach the swap inside exec(), to the ones an outside account can reach, which is where the invariant lives: only the designated operator should be able to make the contract sell.

BugPoCer goes after that rule. Running Counterexample-Guided Invariant Refutation over the contract and the pair it sells into, it executes call sequences from arbitrary accounts until one makes the contract sell, and then extends the sequence to show what an outsider gains, here by trading around the forced sales in the same transaction.

The counterexample is the July 28 attack in compact form: a sale into the Pro/USDT pair, repeated exec() calls from an address that isn't the operator, and a buyback at the lower price that leaves the caller with more USDT than it started with. It comes with the minimal conditions, a caller with no special role and a pair the contract sells into, and a generated Forge test that replays the calls and asserts the outsider profited. Because the engine runs in development, at every merge and before release, it would have surfaced when exec() first shipped without a caller check.

Guard the Timing, Not Just the Funds

The upgrade that fixed this contract took one condition, added after the fact. For builders, any function that trades on a project's behalf needs the same restriction as one that sends funds, because the power to choose when a sale happens is worth money to someone standing on the other side of it. To see how Olympix maps every public path into your treasury and pool logic and returns a runnable counterexample for each one an outsider can reach, book a technical walkthrough.

On-Chain References

Protocol: Crypto DAO Pro token

Chain: BNB Chain

Date: July 28, 2026 (example attack tx at 15:44:54 UTC)

Loss: about $52K attacker profit per GoPlus; 167,200 Pro sold from the exploited contract

Attacker EOA: 0x4276...F45D

Attack contract: 0xf00b...50ac

Exploited contract (proxy): 0xc44f...4A3C

Exploited implementation: 0x7fBA...AA87

Pro token: 0x8D65...F0e2

Pro/USDT pair: 0x6384...50C3

Pro/CDAO pair (flash swap): 0x86ac...30df

Receiver 1: 0xc399...0369

Receiver 2: 0x4e94...38af

Receiver 3: 0xD9c8...7252

ProxyAdmin: 0xb396...e962

ProxyAdmin owner and operator: 0xe561...4a59

Receivers' consolidation contract (owner 0xe561...4a59): 0xc2d8...9a13

Receiver 2 forward (2.6M USDT): 0xb15c...ece1

Receiver 3 forward (2.6M USDT): 0xa4a7...6239

Receiver 1 forward (2.4M USDT): 0x21a3...44ba

Example exploit tx: 0x6a50...0ff4

Block: 112652246

Patch upgrade tx: 0x1755...073c

Patched implementation: 0xF912...0059

Sources

GoPlus Security: Vulnerability analysis of the Crypto DAO Pro attack

DeFiHackLabs PR #1195: Pro Token PoC

The Crypto Times: Crypto DAO Drained for $8.2M on BNB Chain via Access Control Bug

More from Olympix:

No items found.

Ready to Shift Security Assurance In-House? Talk to Our Security Experts Today.