AISPACE Pair Spoofing and Vault Drain
Exploit Transactions
0x0be817b6a522a111e06293435c233dab6576d7437d0e148b45efcf7ab8a10de0Victim Addresses
0x6844ef18012a383c14e9a76a93602616ee9d6132BSC0xffac2ed69d61cf4a92347dcd394d36e32443d9d7BSC0x1219f2699893bd05fe03559aa78e0923559cf0cfBSCLoss Breakdown
Similar Incidents
CS Pair Balance Burn Drain
41%StarlinkCoin Pair Drain
38%LinkdaoDex USDT Pair Drain
37%T3913 Pair-Skim Referral Drain
36%KEKESANTA Pair-to-Router Double-Credit Liquidity Drain
36%Public Mint Drains USDT Pair
36%Root Cause Analysis
AISPACE Pair Spoofing and Vault Drain
1. Incident Overview TL;DR
On BSC block 33916688, transaction 0x0be817b6a522a111e06293435c233dab6576d7437d0e148b45efcf7ab8a10de0 executed a fully permissionless drain against AISPACE. The attacker used a PancakeV3 USDT flash loan, marked an attacker-controlled helper as an AISPACE trading pair through the public setSwapPairs(address) entrypoint, recycled the same AIS through the public Pancake pair skim(address) function to inflate PendingMint, harvested newly minted AIS into the AISPACE market vault, took over that vault through a permissionless setAdmin(address), withdrew the harvested AIS, sold it for USDT, repaid the flash loan plus fee, and kept 60686.884783691370295991 USDT.
The root cause is an access-control failure on two separate public privilege surfaces. AISPACE allowed arbitrary callers to mutate the trusted-pair set that drives mint accounting, and the market vault allowed arbitrary callers to replace the vault admin. Together those bugs made the mint-credit path and the withdrawal path fully exploitable by any unprivileged actor.
2. Key Background
AISPACE is not a plain ERC-20. Its transfer path branches on Pairs[address], and those branches mutate PendingMint and PendingBrun. When Pairs[from] is true, the transfer credits PendingMint by 4% of the transfer amount and sets a 5% pending burn on the receiver. When Pairs[to] is true, the transfer credits PendingMint by 8% and sets a 10% pending burn on the sender. harvestMarket() later mints PendingMint - MintPosition directly into MarketAddress.
The public PancakeSwap V2 pair at 0x1219f2699893bd05fe03559aa78e0923559cf0cf exposes skim(address), which transfers any token balance above recorded reserves to an arbitrary recipient. That matters because the attacker could send AIS into the pair, let AISPACE account the transfer as pair-related, and then immediately pull the same AIS back out without changing reserves.
The market vault at 0xffac2ed69d61cf4a92347dcd394d36e32443d9d7 held the harvested AIS. Pre-state permission checks in the collected RPC observations show setAdmin(address) succeeded for a random caller, while transferToken(address,address,uint256) reverted only until the caller first rewrote the mutable admin slot.
The ACT pre-state is BSC mainnet immediately before block 33916688, which is block 33916687 in the collected fork configuration. In that pre-state, the real AIS/USDT pair was already flagged in Pairs, the attacker helper was not, the flash pool 0x4f31fa980a675570939b737ebdde0471a4be40eb exposed a USDT/USDC pool with fee 500, and AISPACE's MarketAddress already pointed at the vulnerable market vault.
3. Vulnerability Analysis & Root Cause Summary
The exploit is an ATTACK-class ACT opportunity, not a privileged insider event. The first broken invariant is that only protocol-approved AMM pairs should be able to trigger AISPACE's pair-tax accounting. AISPACE violates that invariant because setSwapPairs(address) is public and directly flips Pairs[_address] = true.
The second broken invariant is that only protocol governance should control market-vault withdrawals. The vault violates that invariant because a public caller can replace the admin and then satisfy the only authorization check on transferToken.
Once the attacker controls both surfaces, the rest of the exploit becomes deterministic. The attacker buys AIS with public flash liquidity, loops transfer -> skim to manufacture PendingMint without consuming the AIS principal, harvests that protocol-side mint into the vault, seizes vault admin, withdraws the harvested AIS, and dumps it into the public AIS/USDT pair for profit.
The exploit conditions were also public and concrete: AISPACE had to expose setSwapPairs(address) without access control, the market vault had to keep setAdmin(address) permissionless while gating withdrawals only by the mutable admin slot, the public AIS/USDT pair had to expose skim(address) and hold enough USDT liquidity, and a public flash-liquidity venue had to exist for the initial AIS purchase. Those are exactly the conditions observed in the validated artifacts.
The violated security principles are clear: arbitrary callers must not be able to assign protocol privileges, mint-accounting logic must not trust attacker-controlled role classification, and vault-withdrawal authority must not be separable from governance through a public setter.
4. Detailed Root Cause Analysis
The relevant AISPACE code from the verified source is straightforward:
function setSwapPairs(address _address) public {
Pairs[_address] = true;
}
function harvestMarket() public {
require(PendingMint > MintPosition, "No Pending available");
_mint(MarketAddress, PendingMint - MintPosition);
MintPosition = PendingMint;
}
function _transferAIS(address from, address to, uint256 value) private returns (bool) {
if (Pairs[from]) {
_transfer(from, to, value);
PendingBrun[to] = value * 5 / 100;
PendingMint += value * 4 / 100;
IMarketVault(MarketAddress).addMarketValue(value * 4 / 100);
return true;
}
if (Pairs[to]) {
require(balanceOf(from) > value * 111 / 100, "insufficient funds for burn!");
_transfer(from, to, value);
PendingBrun[from] = value * 10 / 100;
PendingMint += value * 8 / 100;
IMarketVault(MarketAddress).addMarketValue(value * 8 / 100);
return true;
}
...
}
That source shows the full code-level breakpoint. Any caller can mark an arbitrary helper as a trusted pair, and once either side of a transfer is treated as a pair, AISPACE credits PendingMint directly from transfer volume rather than from any real economic gain.
The vault-side evidence is equally explicit in the collected pre-state checks:
"permission_checks_pre": {
"set_admin_from_random_address": "success",
"transfer_token_from_random_address": "revert Not admin",
"transfer_token_from_existing_admin": "success"
}
This means a random caller could first take the admin role and then use the vault's token-withdrawal function.
The seed transaction data shows the exploit parameters and post-state:
- Flash borrow:
3000000000000000000000000USDT. - Initial AIS buy:
142406161283037117313874AIS. - Skim loop amount:
128165545154733405582486AIS. - Skim loop count:
100. - Harvested AIS minted to vault:
1543728293469283826814527. - AIS withdrawn from vault:
1389357514498347255584772. - Final AIS sold back to the pair:
1531763675781384372898646. - Flash repayment:
3001500000000000000000000USDT. - Final profit transfer:
60686884783691370295991USDT.
The on-chain trace confirms the exploit sequence includes repeated pair skim calls, then market harvesting and vault seizure:
PancakeV3_USDT_USDC::flash(..., 3000000000000000000000000, ...)
PancakePair::skim(0x15FFd1D02B3918C9e56f75E30D23786D3eF2B5bc) // repeated 100 times
AISPACE::harvestMarket()
AIS_MarketVault::setAdmin(0x15FFd1D02B3918C9e56f75E30D23786D3eF2B5bc)
AIS_MarketVault::transferToken(
AISPACE,
0x15FFd1D02B3918C9e56f75E30D23786D3eF2B5bc,
1389357514498347255584772
)
The exploit therefore breaks two explicit invariants:
- Pair status must not be mutable by arbitrary callers when pair status controls mint accounting.
- Vault withdrawal authority must not be rewritable by arbitrary callers.
Because both invariants were broken in the public pre-state, the exploit was reproducible by any unprivileged actor from the same block state. The success predicate is both monetary and non-monetary: the attacker realized 60686.884783691370295991 USDT profit, and an arbitrary caller could force unauthorized AIS minting plus USDT reserve drain from the public pair.
5. Adversary Flow Analysis
The adversary cluster in the validated analysis has three roles:
0x7cb74265e3e2d2b707122bf45aea66137c6c8891: the EOA that sent the exploit transaction and paid the BNB gas cost.0x15ffd1d02b3918c9e56f75e30d23786d3ef2b5bc: the helper contract that executed the flash loan, pair spoofing, skim loop, vault takeover, token withdrawal, liquidation, and repayment.0x859444a27eff21b443f6213ec54fd2f1a09de346: the EOA that received the final USDT profit transfer.
The full exploit flow is:
- The helper contract borrows
3,000,000USDT from PancakeV3 pool0x4f31fa980a675570939b737ebdde0471a4be40eb. - It swaps the borrowed USDT through PancakeRouterV2
0x10ed43c718714eb63d5aa57b78b54704e256024einto142406.161283037117313874AIS. - It calls
AISPACE.setSwapPairs(helper)to whitelist itself as a trusted pair even though it is attacker-controlled. - It loops
helper -> pair transferfollowed bypair.skim(helper)100 times, recycling128165.545154733405582486AIS per loop while repeatedly creditingPendingMint. - It calls
AISPACE.harvestMarket(), which mints1543728.293469283826814527AIS into the market vault. - It calls the vault's public
setAdmin(helper), thentransferToken(AIS, helper, 1389357.514498347255584772). - It sells
1531763.675781384372898646AIS back into the AIS/USDT pair, receives3062186.884783691370295991USDT, repays3001500USDT to the flash pool, and transfers60686.884783691370295991USDT to the profit EOA.
Every step above used public contracts and public state. No private key compromise, governance privilege, or attacker-only bytecode dependency was required.
6. Impact & Losses
The measurable loss is the AIS/USDT pair depletion of 62186.884783691370295991 USDT, recorded in the balance diff as raw amount "62186884783691370295991" with 18 decimals. The flash pool also collected the 1500 USDT fee that explains the difference between pair loss and attacker profit.
The attack also created protocol-side inflation that should never have existed. AISPACE.harvestMarket() minted 1543728.293469283826814527 AIS into the market vault, and the attacker then withdrew 1389357.514498347255584772 AIS from that vault before dumping 1531763.675781384372898646 AIS into the public pair. That sequence both drained USDT reserves and left the market vault and pair holding distorted AIS balances.
7. References
- Seed exploit transaction:
0x0be817b6a522a111e06293435c233dab6576d7437d0e148b45efcf7ab8a10de0on BSC block33916688. - AISPACE token contract:
0x6844ef18012a383c14e9a76a93602616ee9d6132. - AISPACE market vault:
0xffac2ed69d61cf4a92347dcd394d36e32443d9d7. - AIS/USDT Pancake pair:
0x1219f2699893bd05fe03559aa78e0923559cf0cf. - PancakeV3 flash-loan pool:
0x4f31fa980a675570939b737ebdde0471a4be40eb. - Evidence used: AISPACE verified source, seed transaction trace, balance diff, and validated RPC observations collected in this session.