Move language vulnerabilities in disclosed bug bounty reports
Move's resource model makes several classic bug classes unrepresentable — and concentrates the remaining risk in capabilities and access rules.
- Reports indexed
- 37
- Total paid
- $180k
- Critical
- 0
- Largest payout
- $180k
Move was designed with digital assets as first-class linear resources: they cannot be copied or silently dropped, and the type system enforces it. That removes an entire family of double-spend and accounting bugs at the language level, which is why the disclosure volume here is thinner and skewed toward design rather than implementation.
What remains concentrates in capability handling. A capability is a transferable right, and a program that stores one carelessly, exposes it through a public function, or grants it during initialization without a corresponding revocation path has handed over the privilege it was protecting.
Aptos and Sui diverge enough in their object and ownership models that findings rarely transfer between them cleanly, so the reports here are worth reading with the specific runtime in mind.
What reviewers look for
- Capabilities exposed through public entry functions
- Resources stored under an address the module does not control
- Generic type parameters not constrained to expected abilities
- Object ownership transfers without an accompanying authorisation check
- Init-time privileges with no revocation path
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
Unchecked arithmetic in Move coin split enables balance underflow
A custom coin-splitting helper in a Move-based decentralized exchange implemented unsafe u128 downcasting that bypassed native Move checked arithmetic. Combined with a stale balance check preceding an internal callback, an attacker could request a swap amount exceeding their actual balance. The resulting u128 subtraction underflow truncated upon downcasting into a valid u64 value, crediting the attacker with an artificially inflated balance that could subsequently be drained from the exchange.
PoolTogether: Resetting delegation will result in user funds being lost forever
The PoolTogether protocol contained a critical logic vulnerability in the TwabController that allowed users to permanently lose access to their funds. By passing an address(0) as a delegate target, users inadvertently triggered a transfer of their balance to the null address, which could not be recovered or withdrawn. The issue was reachable via standard user interaction with the delegation system and mattered because it resulted in an irreversible loss of capital for the affected user.
Current Finance: Multiply-before-divide overflow in update_pool_reward_manager permanently freezes all lending operations for affected CoinType
A high-severity arithmetic overflow in Current Finance's reward manager permanently freezes all lending operations for a given CoinType on Sui. The bug is a multiply-before-divide in the reward unlock calculation: `total_rewards * time_passed` overflows the decimal-safe bound before the normalization by the reward duration is applied, aborting every transaction. With realistic reward configurations (e.g., 500K USDC over 30 days), just ~10 hours of pool inactivity triggers the abort, and since the update timestamp never advances, the pool enters an irrecoverable deadlock blocking deposits, withdrawals, borrows, repays, liquidations and reward claims, risking bad-debt accumulation and loss of user funds.
Current Finance: Double subtraction of cash_reserve in deposit_limit_breached allows bypassing the maximum deposit limit
Current Finance's Sui Move lending market enforces a per-asset maximum deposit cap through the deposit_limit_breached guard, but that guard subtracts cash_reserve twice when computing the current pool size. Because total_deposit_plus_interest already reduces the pool to the users' pure stake (cash + debt - cash_reserve), the extra subtraction deflates the measured deposit total by the size of the accrued reserve. As a result, deposits that would push real user deposits above the configured max_deposit_amount are accepted, and the cap becomes progressively ineffective as protocol fees accumulate, weakening the market's risk-management invariant on deposit sizing.
Current Finance: Cross-segment limiter netting failure lets attackers grief daily borrow and withdraw caps
Current Finance's market limiter is meant to enforce a rolling net-outflow cap on borrowing and withdrawals, storing usage in per-segment buckets. However, while adding outflow charges the current segment, reducing outflow (repayments or redeposits) only mutates the current segment and total usage sums all live segments in the window. As a result, an outflow recorded near the end of one segment cannot be unwound in a later segment, so the earlier bucket stays fully charged for the rest of the cycle. An attacker can borrow or withdraw right before a segment boundary, unwind right after the next segment starts, and leave the cap saturated at no residual capital risk. This griefs legitimate users by blocking borrows and withdrawals, an availability impact the assigned medium severity reflects.
Current Finance: Expired reward pool close can refund economically accrued borrower yield before lazy reward materialization
Current Finance's Sui-based lending protocol has a lifecycle flaw in closing expired borrow liquidity-mining pools. Because new reward pools are created with zero per-borrower trackers and those trackers are materialized lazily (only on the borrower's next interaction or claim), a borrower who deposited before the campaign can accrue rewards through the global total_shares and cumulative_rewards_per_share math while never appearing in the pool's num_obligation_reward_managers counter. The close_pool_reward path gates refunds on that counter being zero without first refreshing the pool, so closing an expired pool refunds the full remaining balance to the close caller even though the normal claim path would have paid the same value to the borrower. After the close, the borrower's later claim fails, making the reward permanently lost. A Move PoC demonstrates economic equivalence between the control (claim-first) and exploit (close-first) paths, proving the refund is the borrower's accrued yield, not campaign dust.
All reports in this group
- Current Finance: ADL borrow deleverage triggers on global debt instead of per-group debt, force-liquidating healthy positionsLogic error$0
- Current Finance: Whitelisted liquidation bots will seize collateral from borrowers that are still solvent at spot price during EMA lagLogic error$0
- BMX Deli Swap: Finalize-window vote-changing vulnerability: auto-voters can alter choices post-epoch to manipulate resultsLogic error$0
- ZetaChain Cross-Chain: SUI receiver lacks validationLogic error$0
- ZetaChain Cross-Chain: SUI TSS drained due to lack of refund when the `withdraw/withdraw_and_call()` PTB failsLogic error$0
- Chakra: Permanent loss of user tokens on both chains if `BurnUnlock` mode fails because of flawed burning patternBridge exploit$0
- Superposition: Missing `lower<upper` check in `mint_position`Integer overflow/underflow$0
- Phi: Exposed `_removeCredIdPerAddress` & `_addCredIdPerAddress` allows anyone to cause issues to current holders as well as upcoming onesLogic error$0
- Munchables: Single plot can be occupied by multiple rentersLogic error$0
- Optimism: The LPP challenge period can cause malicious and freeloader claims to be uncounterable and can also cause freeloader claims to be abused to entrap honest challengersOracle manipulation$0
- Optimism: The LPP proposer may not be reimbursed their gas costs by the bonds at `MAX_GAME_DEPTH` because `step()` does not check if the LPP proposer is the one that called itLogic error$0
- Olas: Changing VoteWeighting contract can result in lost staking incentivesFlash loan attack$0
- Panoptic: Removed liquidity can overflow when calling `SemiFungiblePositionManager.mintTokenizedPosition` functionReentrancy$0
- DYAD: Kerosene collateral is not being moved on liquidation, exposing liquidators to lossOracle manipulation$0
- DYAD: Inability to perform partial liquidations allows huge positions to accrue bad debt in the systemFlash loan attack$0
- DYAD: No incentive to liquidate small positions could result in protocol going underwaterLogic error$0
- DYAD: Liquidation bonus logic is wrongOracle manipulation$0
- Renzo: Deposits will always revert if the amount being deposited is less than the `bufferToFill` valueReentrancy$0
- Kintsu: Potential DOS in `delegate_compound` FunctionLogic error$0
- Taiko: Taiko SGX Attestation - Improper validation in certchain decodingLogic error$0
- Salty.IO: Attacker Can Inflate LP Position Value To Create a Bad Debt LoanOracle manipulation$0
- Salty.IO: formPOL lacks slippage and deadline protectionOracle manipulation$0
- Perpetual: Borrow fees can be arbitrarily increased without the maker providing any valueLogic error$0
- Real Wagmi #2 Update: A borrower eligible for liquidation can pay an improperly large amount of fees, and may be unfairly liquidatedLogic error$0
- Collective: MaxHeap.sol: Already extracted tokenId may be extracted againLogic error$0
- NextGen: Auction winner can prevent payments via `safeTransferFrom` callbackLogic error$0
- NextGen: Auction payout goes to `AuctionDemo` contract owner, not the token ownerLogic error$0
- Open Dollar: Malicious users are able to bypass the Tax payment using making a Fake BasicActions ContractLogic error$0
- Wildcat Protocol: Lenders can escape the blacklisting of their accounts because they can move their MarketTokens to different accounts and gain the `WithdrawOnly` Role on any account they wantReentrancy$0
- Tapioca DAO: twAML::participate - reentrancy via _safeMint can be used to brick reward distributionReentrancy$0
- Maia DAO Ecosystem: An attacker can mint an arbitrary amount of `hToken` on `RootChain`Access control$0