Low Findings
Boundary Check for Minimum Borrow Amount
Severity: Low
Ecosystem: Sui
Protocol: Creek Finance
Auditor: MoveBit
Report: https://movebit.xyz/reports/Creek-Audit-Report-2025-12-30.pdf
Report Date: Dec 2025
Description:
In borrow_internal, the condition excludes the valid edge case where the borrow amount equals the minimum allowed value plus the fee.
One-way ownership transfer pattern is Unsafe
Severity: Low
Ecosystem: Supra Chain
Protocol: Dexlyn Hyperlane
Auditor: Hacken
Report: https://hacken.io/audits/dexlyn/sca-dexlyn-hyperlane-monorepo-dec2024/
Report Date: Dec 2024
Description:
In router.move, mailbox.move, and multisig_ism.move, the ownership transfer pattern implemented in functions like transfer_ownership() uses a single-step process where ownership is directly transferred to a new address. If the new owner address is incorrectly specified (typo, wrong address format, etc.), ownership could be permanently lost with no way to recover.
In an edge case transfer will revert despite having sufficient funds
Severity: Low
Ecosystem: Supra Chain
Protocol: Dexlyn Hyperlane
Auditor: Hacken
Report: https://hacken.io/audits/dexlyn/sca-dexlyn-hyperlane-monorepo-dec2024/
Report Date: Dec 2024
Description:
In move/igps/sources/igps.move, the pay_for_gas function's balance check uses a strict greater than (>) comparison instead of greater than or equal to (>=). This causes transactions to revert when a user has exactly the required amount:
assert!(coin::balance<AptosCoin>(account_address) > required_amount, ERROR_INSUFFICIENT_INTERCHAIN_GAS);
Transactions will fail even when users have exactly the required amount of funds to pay for interchain gas. While not a security vulnerability, this creates unnecessary friction and may confuse users who have allocated precisely the required amount.
Zero-Stake Period Leads to Reward Loss
Severity: Low
Ecosystem: IOTA Mainnet
Protocol: Pools Finance
Auditor: Hacken
Report: https://hacken.io/audits/pools-finance/sca-pools-finance-pools-contracts-may2025/
Report Date: June 2025
Description:
A vulnerability exists in the staking protocol's reward accumulation mechanism that causes permanent loss of rewards during periods when no users have staked tokens. The issue stems from the protocol's division-by-zero protection logic that returns zero accumulated rewards when total_staked 0, effectively discarding rewards that should be distributed to future stakers.
Bug in condition when checking we borrowed enough
Severity: Low
Ecosystem: Sui
Protocol: Kai Finance
Auditor: Asymptotic
Report: https://info.asymptotic.tech/kai-leverage-verification-report-6ec808dd2adc4b55a4e30f0512260a70
Report Date: Aug 2024
Description:
It checks for borrowed_x while the function refers to position y(github) . It is not critical because create_position rechecks correctly.
Incorrect treasury empty check
Severity: Low
Ecosystem: Sui
Protocol: Kai Finance
Auditor: Asymptotic
Report: https://info.asymptotic.tech/kai-leverage-verification-report-6ec808dd2adc4b55a4e30f0512260a70
Report Date: Aug 2024
Description:
The treasury check is incomplete in add_lend_facil (github). The condition should be registry.supply_x64() == 0 && registry.underlying_value_x64() == 0 .
create_pool is an example of the correct condition (github).
Not major because it is a function used by the owner of the pool — it just protects against silly mistakes.
Can delete non-empty action group
Severity: Low
Ecosystem: Sui
Protocol: Aeon
Auditor: Asymptotic
Report: https://info.asymptotic.tech/aeon-audit-report#262c1aef2c7042b7816a0015ed4a0051
Report Date: Feb 2025
Description:
execute_config_delete_action_group, does not assert that the group is empty, like execute_config_user_delete_group and execute_config_address_book_delete_group
view_mpc_ready_signing_tx_signable is a getter/viewer so it shouldn't have any asserts
Severity: Low
Ecosystem: Sui
Protocol: Aeon
Auditor: Asymptotic
Report: https://info.asymptotic.tech/aeon-audit-report#262c1aef2c7042b7816a0015ed4a0051
Report Date: Feb 2025
Description:
Can they be moved in process_module_action_result or create_module_action_result?
Cosmos transactions cannot be updated
Severity: Low
Ecosystem: Sui
Protocol: Aeon
Auditor: Asymptotic
Report: https://info.asymptotic.tech/aeon-audit-report#262c1aef2c7042b7816a0015ed4a0051
Report Date: Feb 2025
Description:
In aeon-chains/sources/cosmos_module.move, prepare_signing doesn’t call add_transaction as it should, which means that prepare_signing_accelerate calls get_transaction_borrow_mut and fails.
Missing check in process_vault_module_changes
Severity: Low
Ecosystem: Sui
Protocol: Aeon
Auditor: Asymptotic
Report: https://info.asymptotic.tech/aeon-audit-report#262c1aef2c7042b7816a0015ed4a0051
Report Date: Feb 2025
Description:
In custody/sources/vault.move, process_vault_module_changes should assert!(added_chain_state_data_id_opt.is_some(), EMissingChainState), like the existing assert!(updated_chain_state_data_id_opt.is_some(), EMissingChainState)
set_manager incorrectly logs old manager
Severity: Low
Ecosystem: Sui
Protocol: Bluefin RFQ
Auditor: Asymptotic
Report: https://bluefin.io/blog/doc/bluefin_rfq_audit.pdf
Report Date: Feb 2025
Description:
let old_manager = manager; actually records the new manager instead of the old one.
Incorrect Cooldown Check in withdraw Function
Severity: Low
Ecosystem: Sui
Protocol: SatLayer Sui
Auditor: Asymptotic
Report: https://info.asymptotic.tech/satlayer-audit
Report Date: Mar 2025
Description:
The withdraw function uses an incorrect comparison operator when validating if the cooldown period has passed. The current implementation uses a strict greater than (>) operator, which could lead to users being unable to withdraw their funds at the exact moment when the cooldown period expires.
Executed Orders Cleanup Missing
Severity: Low
Ecosystem: Sui
Protocol: ZO Perps(Sudo)
Auditor: Asymptotic
Report: https://info.asymptotic.tech/sudo-audit-report
Report Date: Mar 2025
Description:
The functions clear_open_position_order and clear_decrease_position_order are the only ones that remove orders from market.orders bag. They handle order cancellation by users (requiring OrderCap) and return their fee and collateral. Users don't need to execute these functions and pay gas fees for already executed orders. As a result, executed orders—both successful and failed—remain permanently stored in market.orders without any cleanup mechanism.
Incorrect Collateral Sufficiency Check in update_emission
Severity: Low
Ecosystem: Sui
Protocol: Full Sail CLMM
Auditor: Asymptotic
Report: https://info.asymptotic.tech/full-sail-clmm-audit
Report Date: May 2025
Description:
The update_emission function in rewarder module checks collateral sufficiency using RewarderGlobalVault::balances instead of available_balance. Since balances includes already settled but unclaimed rewards, this validation is unreliable and could lead to insufficient actual collateral for new emissions.
The daily rewards calculation 86400 * (emission_rate >> 64) performs the shift before multiplication, leading to potential precision loss due to truncation of emission_rate.
The code uses hardcoded literals (86400) instead of named constants.
fetch_ticks Behavior Deviates from Other Fetch Functions
Severity: Low
Ecosystem: Sui
Protocol: Full Sail CLMM
Auditor: Asymptotic
Report: https://info.asymptotic.tech/full-sail-clmm-audit
Report Date: May 2025
Description:
The fetch_ticks function in the tick module behaves inconsistently compared to other fetch_* functions.
It skips the tick at tick_indexes[0] itself, starting from the next tick(include parameter in find_next function is set to false). This differs from other fetch functions, which typically include the starting element, and can lead to unexpected omissions or developer confusion.
Additionally, fetch_ticks function does not check the limit in the while loop condition, only inside the loop body. As a result, if the limit is set to zero, the loop still runs and continues fetching until the end of the list, since the break condition if (new_count == limit) is never satisfied. While a limit of zero could be interpreted as "fetch all", this behavior is not aligned with the comments or how limits are handled in similar functions.
repay_flash_swap Ignores partner_id
Severity: Low
Ecosystem: Sui
Protocol: Full Sail CLMM
Auditor: Asymptotic
Report: https://info.asymptotic.tech/full-sail-clmm-audit
Report Date: May 2025
Description:
repay_flash_swap called after flash_swap_with_partner ignores the partner_id, but this is not an issue, because it checks that ref_rate == 0. Still, I would recommend to change the type of partner_id in FlashSwapReceipt to Optionsui::object::ID, and in repay_flash_swap check that it is None.
Pause bypass for reward updates
Severity: Low
Ecosystem: Sui
Protocol: Momentum
Auditor: Sherlock
Report Date: Nov 2025
Description:
The admin entry points uses a pause flag on VeMMT to freeze critical state changes during incidents. Functions that initialize a schedule or extend its duration explicitly check is_paused and abort when true. The emission returning function like update_pool_reward_emission lacks this guard and still calls into the pool to update rate and end-time accounting.
The get_user_claim_reward_amount overestimates claimable reward
Severity: Low
Ecosystem: Sui
Protocol: Momentum
Auditor: Sherlock
Report Date: Nov 2025
Description:
The read path computes the user’s claim by iterating epochs and calculating each epoch’s accrual from index deltas and vote power. For each epoch, it caps the computed value by the current pool balance. Because it does not model a running “remaining pool balance,” it may cap multiple epochs against the same balance snapshot and sum a total larger than the coin the pool can transfer atomically. Additionally, the view reads time-sensitive fields like current index or end-of-epoch markers without first calling the pool’s sync_or_advance_epoch sync routine, so the calculation can be stale within an epoch.
View helpers abort for unstaked ve-tokens
Severity: Low
Ecosystem: Sui
Protocol: Momentum
Auditor: Sherlock
Report Date: Nov 2025
Description:
The build_ve_token_data view builder composes a position object by pulling claimable rewards, last-claimed markers, and other reward fields via helpers that borrow the UserRe wardData dynamic field from the VeToken. That dynamic field exists only for staked tokens that have been deposited through deposit. The builder computes “staked or not” later in the flow using is_ve_staked, so the early attempt to borrow UserRewardData on an unstaked token aborts the view call. Read-only endpoints that rely on build_ve_token_data inherit the same failure mode.
Initialization Function Can be Called Multiple Times
Severity: Low
Ecosystem: Sui
Protocol: Momentum
Auditor: MoveBit
Report Date: Nov 2025
Description:
The initialization function of the StakingPool can be invoked multiple times. Repeated initialization may result in the loss of user funds.
Incorrect Return Value in Binary Search for Optimal Swap Amount
Severity: Low
Ecosystem: Sui
Protocol: Momentum CLMM
Auditor: Asymptotic
Report Date: Aug 2025
Description:
The get optimal swap amount for single sided liquidity function uses a binary search to find the swap amount that best matches the optimal token ratio. While the function correctly tracks the best ratio found during the search, it does not return the swap amount corresponding to this best ratio. Instead, it returns the value calculated for the next iteration, that never runs and may not be optimal. Additionally, the binary search logic can be optimized, as it runs in a loop with some redundant assignments and unnecessarily steps. Simplifying the logic and removing redundant operations would improve both code clarity and execution efficiency.
Incorrect Validation Order: check tick range Called Before Tick Order Check
Severity: Low
Ecosystem: Sui
Protocol: Momentum CLMM
Auditor: Asymptotic
Report Date: Aug 2025
Description:
In open position, check tick range is called before verify tick. However, check tick range assumes tick upper ¿ tick lower but does not check this.
Multiple Identical Pools Enable Liquidity Fragmentation
Severity: Low
Ecosystem: Sui
Protocol: Momentum CLMM
Auditor: Asymptotic
Report Date: Aug 2025
Description:
The pool creation function allows multiple identical pools to be created for the same token pair, which can lead to liquidity fragmentation and user confusion. The current implementation only checks that the two token types are different (X != Y) but does not enforce canonical token ordering.
Incorrect Semantics for unblock(ALL) Operation
Severity: Low
Ecosystem: Sui
Protocol: Cetus CLMM
Auditor: Asymptotic
Report: https://drive.google.com/drive/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Nov 2025
Description:
The restriction system treats ALL as an independent role bit rather than a composite of all operation types. When unblock(entity, ALL) is called after specific operations were blocked, those specific blocks persist. The unblock function only removes the ALL bit, leaving individual operation bits intact. However, the is blocked function correctly checks: If ALL bit is set → return blocked OR if specific operation bit is set → return blocked
Incorrect Event Emission On Multiple Liquidity Additions To Active Bin
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: CertiK
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
The add_liquidity function calculates composition fees when a user adds liquidity to the pool's active bin. However, if a user provides the active bin's ID multiple times within a single call, a logic flaw causes the fees to be underreported in the emitted AddLiquidityEvent . The variables fee_a and fee_b , which track the fees paid, are overwritten in each loop iteration instead of being accumulated. This is possible because the function does not check to ensure the user only add liquidity to the active bin once in a call.
Add/Remove/Repay Liquidity Sequence Allows Flashloan Like Operation With No Cost
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: CertiK
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
The add-liquidity flow mints liquidity and updates ticks immediately, returning an AddLiquidityReceipt with the owed
amount_a and amount_b that must be repaid in the same transaction.
No guard is preventing a user from calling remove_liquidity on the same position before calling repay_add_liquidity .
This permits sourcing the repayment entirely from the pool itself within the same transaction (flashloan-like behavior), i.e.,
add_liquidity -> remove_liquidity ->
By Paying Swap Fees To Avoid Composition Fees From Unbalanced Liquidity During add_liquidity() And open_position()
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: CertiK
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
Since users can utilize the already added liquidity for operations between add_liquidity() / open_position() and repay_add_liquidity() , when users need to add liquidity at an unbalanced amount_a/amount_b ratio in the active bin, they can pay swap fees through a certain method to avoid composition fees caused by unbalanced ratio.
fetch_bins() Fetches Bins From The Start Of BinGroup Instead Of The Start Bin ID
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: CertiK
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
The previous version of fetch_bins() would return limit consecutive existing bins in the pool starting from the start bin ID. However, in the current code, since the idx in fetch_bins() is calculated starting from 0, it returns limit consecutive existing bins in the pool starting from the first bin of the BinGroup where start resides.
Discussion On reward_refunded
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: CertiK
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
During reward_settle() , if the emergency reward pause is activated, rewards are temporarily stored in the reward_refunded variable and will only be distributed once the active bin becomes empty. However, in a well-functioning pool, the active bin becoming empty is a very rare event. If this condition does not occur for along time, the funds stored in reward_refunded will remain locked in the contract and cannot be released.
Fee Sync Blocked By Reward Permission In update_position_fee_and_rewards
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: CertiK
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
In pool.move, update_position_fee_and_rewards ties two unrelated permissions together by calling operation_check twice, once with COLLECT_FEE and once with COLLECT_REWARD , before doing any state updates: pool.operation_check(restriction::collect_fee_kind(), ...) pool.operation_check(restriction::collect_reward_kind(), ...) operation_check asserts the corresponding pool permission flags are not disabled. As a result, update_position_fee_and_rewards will revert if either disable_collect_fee or disable_collect_reward is true, even though the function only performs internal accounting updates and does not actually transfer assets. As a result, when rewards are paused ( disable_collect_reward = true) but fee collection is allowed ( disable_collect_fee = false), LPs cannot call update_position_fee_and_rewards due to the collect_reward check, so users cannot bring their position’s fee counters up to date and will collect stale/partial fees. This creates a potential unintended denial of fee withdrawals whenever rewards are paused.
Missing Token Pair Sorting in Pool Key Generation
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: MoveBit
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
The new_pool_key function does not sort CoinTypeA and CoinTypeB before generating the pool key, which can lead to the creation of duplicate pools for the same token pair in different orders.
Missing Validation of Current Time vs End Time in create_partner
Severity: Low
Ecosystem: Sui
Protocol: Cetus DLMM
Auditor: MoveBit
Report: https://drive.google.com/drive/u/0/folders/1d9nv3nJidsbQ0vDT8D1kEuR3rJzK2ULg
Report Date: Sep 2025
Description:
An incomplete time validation logic issue has been identified in the create_partner function within partner.move. Missing Validation: There is no check to ensure that end_time is greater than the current time. This allows the creation of a partner that has already expired at the moment of creation.
Improper Convergence Checks
Severity: Low
Ecosystem: Sui
Protocol: Aftermath
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2023
Description:
In the geometric_mean_calculations.move module within the following functions: calc_swap_fixed_in, calc_swap_fixed_out, calc_withdraw_fixed_amounts, and calc_deposit_fixed_amounts, the convergence between prev_t and t is checked after the while loop. However, this approach will properly execute because the t value is copied into the prev_t variable at the end of the loop.
Improper Token Weight Calculation
Severity: Low
Ecosystem: Sui
Protocol: Bucket
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: June 2023
Description: get_token_weight in the tank module calculates the weight of the user’s deposit. Calculating the amount able to be withdrawn by the user uses this token weight. In this function, if the total calculated compound_stake of the user for the two scales is less than token.deposit_amount/constants::scale_factor() value, zero is returned. This results in unnecessarily reducing the user’s compounded stake.
Incorrect Key Check
Severity: Low
Ecosystem: Sui
Protocol: Scallop
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: June 2023
Description:
obligation::lock is designed to lock the obligation functionality. Currently, the function invokes assert_reward_key_in_store, which is inconsistent with its intended purpose. Instead, assert_lock_key_in_store should be invoked, as the function should handle the locking of the obligation, not the rewards management.
Excessive Withdrawal Of Staked Amount
Severity: Low
Ecosystem: Sui
Protocol: Haedel LSD
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Nov 2023
Description: The issue stems from the existing implementation of get_split_amount, where a modest need_amount (e.g., 1 MIST) has the potential to trigger the withdrawal of the entire StakedSui, even if the total staked SUI amount is considerably high, instead of withdrawing only a portion of the staked amount as intended, and keeping the rest staked.
Non-Ascending Epoch Claims
Severity: Low
Ecosystem: Sui
Protocol: Haedel LSD
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Nov 2023
Description:
The issue is with regards to set_withdraw_time_limit, which grants administrators the ability to define the time limit for withdrawing staked tokens. To elaborate, should the administrator elevate the withdraw_time_limit to surpass the present timestamp calculated from the inception of the epoch, it may result in a scenario where a user generates two UnstakeTicket objects within the same epoch. In particular, if the timestamp (X) of the first ticket exceeds epoch_timestamp_ms + old_limit, and the timestamp (Y) of the second ticket falls below epoch_timestamp_ms + new_limit, the resultant EpochClaim for these two tickets will correspond to epochs E+2 and E+1, respectively. This creates a scenario where the epoch claims are in a non-ascending order, which is problematic as epoch claims should be in ascending order. This non-ascending order may disrupt the normal flow of epochbased operations.
Invalid Parameters
Severity: Low
Ecosystem: Sui
Protocol: Drife Technologies
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Dec 2023
Description: The issue is related to the fact that both stop_ride and resume_ride functions expect Driver and Rider objects to be passed as arguments at the same time. It should be impossible for the user to own both Driver and Rider objects.
Arrival Confirmation
Severity: Low
Ecosystem: Sui
Protocol: Drife Technologies
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Dec 2023
Code: N/A
Description:
In its current implementation, the system allows a driver to start a ride without confirmation from the rider that they have arrived at the pickup point. This lack of confirmation can lead to potential issues such as miscommunication or misunderstandings between the rider and the driver, affecting the system’s overall customer experience and functionality.
Improper Fee Configuration
Severity: Low
Ecosystem: Sui
Protocol: Aftermath Orderbook
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Feb 2024
Description: Fees could be negative, giving collateral to user instead of paying fees.
Rewards State Abort
Severity: Low
Ecosystem: Sui
Protocol: Suilend
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Apr 2024
Description: An edge case occurs when the length of the rewards vector in user_reward_manager is less than or equal to the current index i. This implies that there are fewer entries in the rewards vector than expected based on the iteration index. However, the if condition vector::length(&user_reward_manager.rewards) == i) only executes when the pool rewards is initialized. If the pool reward array is not contiguous, this could trigger an abort.
Ownership Transferring Not Tracked
Severity: Low
Ecosystem: Sui
Protocol: Sui Axelar(Gateway V2)
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2024
Description: There is an issue within process_commands in the Cross-Chain Gateway Protocol, specifically in the handling of ownership transfer calls (SELECTOR_TRANSFER_OPERATORSHIP). Currently, the function only records approved token transfer calls and does not record calls that transfer ownership. This omission opens up the possibility of relay attacks.
Potential Balance Misallocation
Severity: Low
Ecosystem: Sui
Protocol: Sui Axelar(Gateway V2)
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2024
Description: In get_transaction, the call to sweep is not explicitly enforced to occur after the call to swap. If the program calls SWAP_TYPE_SWEEP_DUST before SWAP_TYPE_DEEPBOOK_V2, or if there is no SWAP_TYPE_DEEPBOOK_V2 call at all, all balances of the base coin (which are supposed to be the remaining coins after the swap) will be stored in the coin_bag of the Squid router during sweep. As a result, if sweep is called before swap, all balances of coin T1 will be moved to the coin_bag of the Squid router, and neither the source nor the destination address will receive any coins. The finalize function includes a safeguard to ensure that the balance value (balance.value()) is greater than or equal to self.min_out. However, this safeguard is ineffective if min_out is set to zero.
Incorrect Whitelist Check
Severity: Low
Ecosystem: Sui
Protocol: Cetus
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2024
Description: config::check_token_and_min_trade_amount misuses the return value of find_token_and_min_trade_amount when require_check_token_white_list is true. The is_existed flag indicates the presence of the token in the whitelist. If it is true, the function should verify the minimum trade amount. Conversely, if is_existed is false, meaning the token is absent from the whitelist, the function should immediately return false.
Double Counting Rewards
Severity: Low
Ecosystem: Sui
Protocol: Turbos Finance
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2024
Description: When strategy_rewards_settle calls accumulate_rewarder_released for each rewarder, it updates the total_reward_released for the entire rewarder based on the current time and the elapsed time since the rewarder’s last_reward_time. The subsequent call to accumulate_strategy_reward also calculates elapsed time using the strategy’s last_reward_time, which may differ from the rewarder’s last_reward_time. Since accumulate_strategy_reward does not update the rewarder’s last_reward_time, the elapsed time it calculates may include a period already accounted for in the previous call to accumulate_rewarder_released. As a result, the total_reward_released for the rewarder may be incremented twice for the same elapsed period, effectively double-counting the reward.
Unhandled Proposal Removal
Severity: Low
Ecosystem: Sui
Protocol: Mysten Deepbook
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Aug 2024
Description: In governance::adjust_vote, when a proposal is removed by remove_lowest_proposal and a new proposal is subsequently created by the same account, certain issues may arise. After a proposal is removed, its ID becomes invalid in the self.proposals map. If the same account creates a new proposal, it may be assigned the same proposal_id; however, the vote count for this new proposal starts at zero.
Imbalance in LST Supply
Severity: Low
Ecosystem: Sui
Protocol: Solend Liquid Staking
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Oct 2024
Description:
Currently, create_lst_with_stake does not validate the relationship between the SUI, fungible_staked_sui, and lst_treasury_cap.total_supply values. The function only ensures that lst_treasury_cap.total_supply and the total staked SUI in the system are greater than zero.
The LST created should ideally represent a proportional claim on the underlying staked SUI assets. If there is no relationship between the total LST supply and the staked SUI, users may receive LST tokens that over- or under-represent the actual value of the staked assets. The misalignment between LST and staked SUI may result in incorrect pricing when users interact with the protocol.
Abort due to Failed Assertion Check
Severity: Low
Ecosystem: Sui
Protocol: Solend Liquid Staking
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Oct 2024
Description:
The assertion in mint within liquid_staking , while intended to maintain the balance between Liquid Staking Tokens ( LST ) and SUI, may abort under certain conditions. If old_lst_supply == 0 and old_sui_supply > 0 , the assertion will always fail. In this case, the conversion of the provided SUI amount to LST utilizing sui_amount_to_lst_amount will return the sui_amount itself.
Incorrect Price Boundary Checks
Severity: Low
Ecosystem: Sui
Protocol: Bluefin Spot
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Nov 2024
Description:
Utilizing >= and <= in the boundary checks is not appropriate, as allowing the price to hit the exact minimum or maximum boundaries will result in attempts to execute swaps that lead to invalid price states.
Incorrect Role Check
Severity: Low
Ecosystem: Sui
Protocol: Matrixdock
Auditor: Zellic
Report: https://github.com/Zellic/publications/blob/master/Matrixdock XAUm - Zellic Audit Report.pdf
Report Date: July 2025
Description: In the revoke_set_revoker function, it checks if the sender is the operator. While all functions with the revoke_ prefix are only callable by the revoker, when setting the revoker, it would be more appropriate to check if the sender is the owner. This is because the operator is only responsible for operations related to minting and burning coins.
Improper Zero Mint Check
Severity: Low
Ecosystem: Sui
Protocol: Aftermath Market Making
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Jan 2025
Description: In end_deposit_session, the check assert!(lp_to_mint != 0 only ensures that the lp_to_mint value, as calculated before the conversion to a fixed-point format ( to_balance ), is non-zero. However, the conversion process itself (specifically the call to ifixed::to_balance ) may still result in a minted amount of zero liquidity provider (LP) tokens, even if the value of lp_to_mint is non-zero prior to conversion.
Risk of Excess Recall Amount
Severity: Low
Ecosystem: Sui
Protocol: Solend Steamm
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Feb 2025
Description:
The logic in bank::recall may result in a situation where the amount_to_recall becomes greater than the available reserves due to the utilization of max(bank.min_token_block_size). The amount_to_recall is adjusted to ensure it is at least the size of bank.min_token_block_size. On recalling an amount smaller than the min_token_block_size , the function will automatically increase the recall amount to the minimum block size. The issue occurs if the available funds (the reserves in the bank) are not large enough to accommodate the adjusted amount_to_recall.
Bypassing Stake Threshold Check
Severity: Low
Ecosystem: Sui
Protocol: Mysten Walrus
Auditor: OtterSec
Report:
https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Mar 2025
Description:
ActiveSet::update does not enforce a minimum stake threshold ( set.threshold_stake ), unlike insert . This introduces a vulnerability where a user may manipulate their stake to gain a position in the active set below the required threshold.
For example, a user may stake an amount greater than set.threshold_stake, ensuring that their node is successfully inserted via ActiveSet::insert. If the active set is full, the node with the lowest stake is removed to accommodate the new entry. After successfully inserting, the user immediately calls ActiveSet::update to lower their stake below set.threshold_stake. As a result, the attacker secures a place in the active set without the required stake amount.
collect function Parameter Checking May Fail
Severity: Low
Ecosystem: Sui
Protocol: FlowX Finance
Auditor: MoveBit
Report: https://movebit.xyz/reports/FlowX-Final-Audit-Report.pdf
Report Date: May 2024
Description:
The collect function only allows the count_x_requested and count_y_requested to both be non-zero in order to pass the check_zero_amount function and if the user's position has only one token in it, he must be forced to pass one of them as an arbitrary value in order to call the collect function.
Lack of Events Emit
Severity: Low
Ecosystem: Sui
Protocol: FlowX Finance
Auditor: MoveBit
Report: https://movebit.xyz/reports/FlowX-Final-Audit-Report.pdf
Report Date: May 2024
Description:
The contract lacks appropriate events for monitoring sensitive operations, which could make it difficult to track sensitive actions or detect potential issues.
Missing Emit Event
Ecosystem: Sui
Protocol: Kuna Labs Yield Optimizer
Auditor: MoveBit
Report: https://movebit.xyz/reports/Yield-Optimizer-Final-Audit-Report.pdf
Report Date: Nov 2023
Description:
The smart contract lacks appropriate events for monitoring sensitive operations(such as managing assets and modifying key configs), which could make it difficult to track important actions or detect potential issues.
Unnecessary Parameter
Severity: Low
Ecosystem: Sui
Protocol: Cetus Farming Smart Contracts
Auditor: MoveBit
Report: https://movebit.xyz/reports/Cetus-Farming-Smart-Contract-Final-Audit-Report.pdf
Report Date: Jan 2024
Description:
In the collect_fee function, the parameters coin_a and coin_b are redundant. The return value after calling the clmm_pool::collect_fee function is the balance type, and there is no need to call the join function.
Incorrect Assert Location
Severity: Low
Ecosystem: Sui
Protocol: Cetus Farming Smart Contracts
Auditor: MoveBit
Report: https://movebit.xyz/reports/Cetus-Farming-Smart-Contract-Final-Audit-Report.pdf
Report Date: Jan 2024
Description:
Assert of the reward_balance and amount quantities are ineffective when placed after the split function, they should be placed before.
set_prize_rate Should Check If It Is New Rate
Severity: Low
Ecosystem: Sui
Protocol: Random-Vault
Auditor: MoveBit
Report: https://movebit.xyz/reports/Random-Vault-Final-Audit-Report.pdf
Report Date: Feb 2024
Description:
In config.move , there should be assertion to check that in set_prize_rate function, config.prize_rates != rates .
queryWinRate Does Not Handle User Withdrawed
Severity: Low
Ecosystem: Sui
Protocol: Random-Vault
Auditor: MoveBit
Report: https://movebit.xyz/reports/Random-Vault-Final-Audit-Report.pdf
Report Date: Feb 2024
Description:
In the design of the lottery.move once a user withdraws any amount in a round, he will not be able to participate in the lottery, which means he has a win rate of 0. However, the queryWinRate function, does not handle such a case but directly computes the win rate using its share. This will lead to confusion of the user and a poor user experience.
Possible Zero Token Minted in mint_market_coin Function
Severity: Low
Ecosystem: Sui
Protocol: Scallop
Auditor: MoveBit
Report Date: June 2023
Description:
If balance_sheet.cash + balance_sheet.debt is greater than balance_sheet.market _coin_supply and underlying_amount is relatively small, resulting in a mint_amount of 0. This can lead to a situation where the user deposits funds (underlying_balance), but no MarketCoin shares are minted, resulting in the user not receiving any shares for their deposit.
Suggest Throw abort Instead Of Returning false
Severity: Low
Ecosystem: Sui
Protocol: Legend of Arcadia
Auditor: MoveBit
Report Date: June 2023
Description:
Among the multiple execute functions of the arca module, When the Proposal is not marked complete, it is recommended not to return false, but throw an exception abort at the end of the function, and no transaction will be generated.
get_auction_max_size Missing Check
Severity: Low
Ecosystem: Sui
Protocol: Typus Finance
Auditor: MoveBit
Report Date: May 2023
Description:
In get_auction_max_size, there is no assertion added to the return value of calculate_max_loss_per_unit, assert!(i64::is_neg(&max_loss), E_INVALID_MAX_LOSS); other calls to calculate_max_loss_per_unit are added.
The Method for Obtaining coin_decimals is Incorrect
Severity: Low
Ecosystem: Sui
Protocol: Navi
Auditor: MoveBit
Report Date: July 2023
Description:
In the init_reserve() function, coin_decimals should not be passed in as a parameter, but should be obtained through the CoinType.
Redundant assert Statements
Severity: Low
Ecosystem: Sui
Protocol: KriyaDEX
Auditor: MoveBit
Report Date: May 2023
Description:
The assert validation always passes when adding liquidity because its condition is the same as the previous if statement.
The Condition of the Assert is Incorrect
Severity: Low
Ecosystem: Sui
Protocol: KriyaDEX
Auditor: MoveBit
Report Date: May 2023
Description:
In the function swap_token_y(), the validation should be for amount > 0 instead of token_y_balance > 0. The same issue also exists in lines 315 and 466.
change_order Function Design Flaw
Severity: Low
Ecosystem: Sui
Protocol: MovEX
Auditor: MoveBit
Report Date: May 2023
Description:
In the change_order function, if the TypeName of the two tokens to be processed is the same, an empty array will be pop_backed and an error will be reported. At the same time, an error will be reported when the TypeName of the two tokens is the same but the length is not equal.
K Value Check Condition Error
Severity: Low
Ecosystem: Sui
Protocol: MovEX
Auditor: MoveBit
Report Date: May 2023
Description:
At the end of the swap function, the value of k in the pool will be limited to an increase, but this is for the case of handling fees. When fee_percent is set to 0, swap will not change the value of k in the pool, so when the limit k is increased, the handling fee Pools with a value of 0 cannot be swapped normally, and the condition of liquidity_before_swap < liquidity_after_swap should be changed to <=.
Function Logic Does Not Match the Annotation
Severity: Low
Ecosystem: Sui
Protocol: Aries Market (Sui)
Auditor: MoveBit
Report Date: June 2023
Description:
When allow_collateral and allow_redeem are set to false, the value of the user's collateral is 0, which will prevent the user from withdrawing, borrowing, etc., and the comment means whether to allow the use of collateral to continue borrowing, and there is a conflict between the two.
Unchecked Return
Severity: Low
Ecosystem: Sui
Protocol: Aries Market (Sui)
Auditor: MoveBit
Report Date: June 2023
Description:
Certain library functions such as coin::burn(), vec_map::remove(), table::remove(), bag::remove(), balance::join(), and balance::decrease_supply() have return values, but are not being properly utilized in the code. Similarly, functions such as market::init_market(), profile::add_profile(), market::add_reserve(), lending::deposit_with_repay(), reserve::repay(), and reserve::deposit_lp_co in() also have return values but are not being properly utilized when called. This could result in important return values not being checked, potentially leading to security vulnerabilities.
Incorrect Event Timestamp Parameter Setting
Severity: Low
Ecosystem: Sui
Protocol: Aries Market (Sui)
Auditor: MoveBit
Report Date: June 2023
Description:
It was identified that within the reserve_status::emit_record_status() function, the record_timestamp parameter was constantly set to 0 when emitting an event.
Logic Repetition
Severity: Low
Ecosystem: Sui
Protocol: Cetus Concentrated Liquidity Protocol (Sui)
Auditor: MoveBit
Report Date: Apr 2023
Description:
The verification logic for positive and negative numbers in the function cmp is consistent.
Abort on Temporary Imbalance During Epoch Transition
Severity: Low
Ecosystem: Aptos
Protocol: Kofi Finance Contacts
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2025
Description:
A strict assertion in update_rewards causes staking operations to fail during temporary imbalances between total kAPT and total staked APT.
Unnecessary Assertion Causes Protocol Lockup
Severity: Low
Ecosystem: Aptos
Protocol: Kofi Finance Contacts
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2025
Description:
The ratio <= RATIO_MAX assertion in math::ratio can permanently lock protocol liquidity if the ratio naturally grows beyond the limit.
Protocol Insolvency via Validator Removal
Severity: Low
Ecosystem: Aptos
Protocol: Kofi Finance Contacts
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2025
Description:
Removing validators may result in irretrievable stake, risking temporary protocol insolvency.
Buffer Vault Drainage Due to Unaccounted Staking Fees
Severity: Low
Ecosystem: Aptos
Protocol: Kofi Finance Contacts
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2025
Description:
Unaccounted staking fees during delegation cause the buffer vault to burn more than it mints, gradually depleting its balance and risking protocol stability.
Faulty Withdrawal Logic
Severity: Low
Ecosystem: Aptos
Protocol: Kofi Finance Contacts
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2025
Description:
delegation_manager::withdraw_stake assumes that withdrawn_amount is always greater than the minimum threshold, risking unexpected aborts if this condition is not met.
Flaw in Reward Withdrawal Logic
Severity: Low
Ecosystem: Aptos
Protocol: Echleon
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Apr 2025
Description:
claim_reward_fa incorrectly utilizes fungible_asset::withdraw, preventing reward claims if the reward FA is dispatchable.
Premature Reward Claiming
Severity: Low
Ecosystem: Aptos
Protocol: Merkle Token
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: July 2024
Description:
The vulnerability in claim_rewards arises from the fact that protocol rewards may be claimed for future epochs or even the current epoch. This is problematic because the rewards for these epochs, as well as the stake distribution, are not yet finalized. Since the total rewards and individual stakes are not finalized for future and current epochs, any claim made during these times may be based on incomplete or inaccurate data. Users may receive more or less than their fair share, resulting in an unfair distribution of rewards.
Permanent Loss Of Expired Rewards
Severity: Low
Ecosystem: Aptos
Protocol: Merkle Token
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: July 2024
Description:
Currently, if rewards are not claimed within a 14-day period, they become inaccessible and may not be retrieved or re-utilized. claim_rewards contains a check that ensures rewards may only be claimed if they are within a 14-day window from their registration. If this period expires, the reward claim fails with the E_CLAIM_EXPIRED error. This rule is meant to ensure that rewards are claimed in a timely manner.
Improper Reward Distribution
Severity: Low
Ecosystem: Aptos
Protocol: TruFin
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2024
Description:
The delegation_pool transfers the add_stake_fees to the NULL_SHAREHOLDER and later returns them to the pool at the end of the epoch. This process occurs because the delegation pool does not distinguish between active and pending_active users, allowing both groups to receive rewards. To ensure active users get their rewards and pending_active users receive their add_stake_fees as rewards in the subsequent epoch, the system imposes add_stake_fees on users. In this protocol, add_stake_fees, which are distributed as rewards in the next epoch, are treated as stake within the same epoch, resulting in the minting of TruAPT. Consequently, users will receive extra rewards from others who are active in the subsequent epoch.
Inappropriate Unlock Amount
Severity: Low
Ecosystem: Aptos
Protocol: TruFin
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2024
Description:
internal_unlock unlocks the amount from the delegation pool and burns the equivalent TruAPT tokens. It creates an UnlockRequest for the user with the unstaked amount, which later facilitates the withdrawal of APT from the protocol. unstaked_apt represents the actual stake amount being unstaked from the delegation pool. Additionally, amount sometimes exceeds the unstaked amount, potentially disbursing more APT than intended. Therefore, it is advisable to utilize unstaked_apt to create the unlock request.
Improper Implementation Of Withdraw All
Severity: Low
Ecosystem: Aptos
Protocol: Thala Labs
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: May 2023
Description:
A pool creator has the option to remove liquidity from the pool by specifying a percentage of liquidity to be removed in bps format. However, if the LBP is still ongoing, only a portion of the liquidity can be removed from the pool, with the entire liquidity only being removable once the LBP has concluded. This is implemented through a check of the remove_bps variable to see if it is equal to BPS_BASE. If this check evaluates as true, an assertion is made to ensure that the LBP has indeed ended before allowing for complete liquidity removal. This can be easily bypassed by passing in remove_bps = 9999 and calling the remove_liquidity multiple times. This removes all the liquidity from the pool even when the LBP has not ended.
Incorrect Variable
Severity: Low
Ecosystem: Aptos
Protocol: Steamflow
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Mar 2023
Description:
In protocol::create, validate_contract_params is utilized to validate the input parameters that are related to amounts. However, the calculate_end, which is responsible for calculating the end-time value used in validate_contract_params, is currently receiving the amount value rather than the amount_per_period value. As a result, calculate_end always returns the end-time value for only one period, which could potentially bypass the end < start + SEVENTY_YEARS_IN_SECS check in validate_contract_params.
Improper Path Validation And Usage
Severity: Low
Ecosystem: Aptos
Protocol: Eternal Finance
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Jan 2023
Description:
In pancake_dex_helper.move, the set_paths function sets a path to be used when reinvesting Cake rewards, verifying whether the path exists or not. When idx = 2, the function checks whether the path Cake -> AptosCoin -> X exists or not. However, in the get_lp_by_cake function, when path = 2, it uses the Cake -> AptosCoin -> Y path to convert the Cake rewards to Y token, which is inconsistent with the validations in the set_paths function. This inconsistency could potentially cause the get_lp_by_cake function to fail. When path = 2, the function attempts to convert Cake rewards from Cake -> AptosCoin -> Y, but this path may not exist.
Faulty Token Struct Comparison
Severity: Low
Ecosystem: Aptos
Protocol: Pancake Swap
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Nov 2022
Description:
In order to construct a deterministic ordering of two tokens in a swap pair, it is necessary to be able to compare them. The current implementation concatenates the address, module, and struct names into a vector and invokes compare_u8_vector. This implementation generates collisions for certain token structs that should not collide. For example, the following two structs would generate the same comparison string. Both structs generate the string: addressFOOBAR. The protocol will incorrectly reject this swap pair from being constructed.
SplayTree Inoperable Remove Functions
Severity: Low
Ecosystem: Aptos
Protocol: Laminar Markets
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Oct 2022
Description:
Functions remove_nodes_greater_than and remove_nodes_less_than don’t work if provided with values greater than the max node and lesser than the min node respectively. When the given scenario is met, the deletion of nodes will not occur.
Ensure Contract Upgrade Integrity
Severity: Low
Ecosystem: Aptos
Protocol: Wormhole Aptos
Auditor: OtterSec
Report: https://ottersec.notion.site/Sampled-Public-Audit-Reports-a296e98838aa4fdb8f3b192663400772
Report Date: Oct 2022
Description:
In both wormhole and token-bridge, contract upgrade via governance is a two step process:
- A user invokescontract_upgrade::submit_vaawith a governance VAA that includes ahash of the intended upgrade code.
- A user invokescontract_upgrade::upgradewith the actualmodule code which subsequently invokes code::publish_package_txn to upgrade the contract. Both of these calls are permissionless (can be invoked by any user). Integrity is protected in the first call by verifying the guardian signatures on the VAA. Integrity is protected in the second call by ensuring the provided module code matches the hash. However, in the original implementation, we identified two issues that would allow an attacker to provide alternative module code that still matches the stored hash:
Serialized Metadata
A module upgrade package contains a list of code modules (vector<vector
Module Boundaries The original hash was computed by first concatenating the code modules and then taking the hash of the concatenated structure. However, this implementation does not properly validate module code boundaries. Specifically, moving N bytes of code from the end of one module to the start of another would not affect the hash:
It is unclear whether an attacker could exploit this collision to deploy a malformed version of the module. However, since the fix is simple, it is preferable to reduce the attack surface as much as possible.
The Necessity of Controlling Return Value Order in the token_reserves() Function
Severity: Low
Ecosystem: Aptos
Protocol: Baptswap
Auditor: MoveBit
Report: https://movebit.xyz/reports/BAPTSWAP-Final-Audit-Report.pdf
Report Date: Dec 2023
Description:
The function token_reserves() adjusts the order of returned values by sorting currencies, which might not be necessary. As the order has already been adjusted before calling this function within the current contract, the if statement is executed every time. To prevent confusion, we believe that the control over the sequence should occur when receiving the return values of this function, rather than within the current function. We also compared this to PancakeSwap's code, which similarly does not control the sequence within the current function.
tp_percent Should Be Less Than or Equal to pair_info.maximum_profit
Severity: Low
Ecosystem: Aptos
Protocol: Merkle Trade Smart Contract
Auditor: MoveBit
Report: https://movebit.xyz/reports/Merkle-Trade-Smart-Contract-Audit-Report.pdf
Report Date: July 2023
Description:
The function execute_increase_order_internal() is responsible for executing an increase order in a trading pair. Inside the function, the stop-loss and take-profit prices of the position are updated based on the order's type and the specified conditions. If the order's take-profit trigger price and the maximum take-profit price are the same, the code will assign that value to the take-profit trigger price of the position. In other words, there is no preference for either value in this scenario, and they are considered equal. However, inside the update_position_tp_sl() , an assertion is made to validate that the calculated take-profit percentage is less than the maximum allowed profit percentage specified in the pair's information. The business logic of this function, update_position_tp_sl() , is different from execute_increase_order_internal() .
Vault Amount Checks Are Not Implemented In Every Operation
Severity: Low
Ecosystem: Aptos
Protocol: Superposition
Auditor: MoveBit
Report: https://movebit.xyz/reports/Superposition-Final-Audit-Report.pdf
Report Date: Mar 2024
Description:
In super postion , the user can perform different operations such as borrow, redeem, repay . And each operation will affect the vault amount differently. However, some operations (repay, redeem) don't have vault checks before and after the operation. And the pre-vault amount calculations are not the same for the other. This would lower the security of the vault and cause misalignment in design.
The verification conditions of assert and if are repeated
Severity: Low
Ecosystem: Aptos
Protocol: Mokshya/Wapal Aptos NFT Mint Smart Contract
Auditor: MoveBit
Report Date: Mar 2023
Description:
In the function candymachine::mint_from_merkle, use assert to verify that is_whitelist_mint is true to continue to execute the code, and then repeat the judgment through if. In the function candymachine::update_candy , assert has been used to verify that publ ic_sale_mint_time >= now && presale_mint_time >= now, and the judgment is repeated through if below.
The assert judgment condition is inaccurate
Severity: Low
Ecosystem: Aptos
Protocol: Aries Market(Aptos)
Auditor: MoveBit
Report Date: Feb 2023
Description:
In the function validate_oracle_info , when sb_weight=0 , pyth_weight=U64_MAX , or sb_weight=U64_MAX , pyth_weight=0 , the assertion condition is not met, causing oracle verification to fail.
Inaccurate judgment on deposit and loan restrictions
Severity: Low
Ecosystem: Aptos
Protocol: Aries Market(Aptos)
Auditor: MoveBit
Report Date: Feb 2023
Description:
In the following functions, when determining whether the deposit and loan amount exceeds the limit, the numerical comparison is inaccurate, and the numerical value should be less than or equal to the limit, not less than.
Incorrect check for minimum order size
Severity: Low
Ecosystem: Aptos
Protocol: Econia
Auditor: Zellic
Report: https://github.com/Zellic/publications/blob/master/Econia - Zellic Audit Report.pdf
Report Date: Jan 2023
Description:
After performing the order book match to attempt to fill a new limit order, the place_limit_order function returns early without placing an order for the remaining unfilled size only if the order is of type IMMEDIATE_OR_CANCEL or if the remaining order size is zero. This is incorrect, as the remaining order size can be lower than the minimum order size configured for the market.
The sendOFT function call can be blocked
Severity: Low
Ecosystem: Aptos
Protocol: Layer Zero OFT Wrapper
Auditor: Zellic
Report Date: Nov 2022
Description:
The contract owner can set any bps value of the variables defaultBps and the oftBps [_oft] in the range from 0 to the maximum BPS_DENOMINATOR inclusive. But during the sendOFT function call, the getAmountAndFees function will check that the final bps value is less than BPS_DENOMINATOR and revert the transaction if it equals or more.
Missing assertion checks for critical protocol parameters
Severity: Low
Ecosystem: Aptos
Protocol: Aptos Dollar
Auditor: Zellic
Report: https://github.com/Zellic/publications/blob/master/Thala Labs Move Dollar - Zellic Audit Report.pdf
Report Date: Oct 2022
Description:
There are no checks in place to enforce that params::set_params
The ascending insertion search fails to return the tail
Severity: Low
Ecosystem: Aptos
Protocol: Aptos Dollar
Auditor: Zellic
Report: https://github.com/Zellic/publications/blob/master/Thala Labs Move Dollar - Zellic Audit Report.pdf
Report Date: Oct 2022
Description:
The sorted_vaults::find_insert_position_ascending search algorithm fails to return the tail position.
Instances of none in VaultStore.vault
Severity: Low
Ecosystem: Aptos
Protocol: Aptos Dollar
Auditor: Zellic
Report: https://github.com/Zellic/publications/blob/master/Thala Labs Move Dollar - Zellic Audit Report.pdf
Report Date: Oct 2022
Description:
Calls to vault::close_vault leave the vault store with a none vault.
Emode LTV & LT invariants can be broken
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
Entering an emode category as a user should never be worse for the user's health. Therefore, functions like pool_configurator::set_emode_category check that the following reserve <>emode[reserve.emodeCategroy] invariant holds.
However, this invariant does not hold because not all functions that can change the reserve's / emode's LTV/LT enforce it.
set_user_emode health check always needs to be performed
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
The emode_logic::set_user_emode function skips the health check when the user goes from noemode to new emode.
The idea is likely that if the following invariants hold, the health can only increase, and therefore set_user_emode cannot be used to turn a healthy user into an unhealthy user.
However, this invariant does not hold because of the finding "Emode LTV & LT invariants can be broken". The impact is that a healthy user can call set_user_emode and end up unhealthy after the call. This is bad for the user as they can be liquidated afterwards. In addition, having a programmatic way for turning any position liquidatable (under the right circumstances) in a single transaction poses security risks (f.i., see the Euler Finance hack analysis by Cyfrin) and protocol bad debt risk.
token_base events do not identify the token used
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
The token_base module is used by all aTokens and vTokens to perform the base token actions like transfers. The emitted Transfer, Mint, Burn events do not identify the actual tokens these events were emitted for. The events are currently not useful for data processing because one can't identify if the Transfer was for aUSDC, aAPT, etc
init_reserves does not support yet the deployment of a reserve with preconfigured incentives_controllers
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
The current implementation of pool_configurator::init_reserves does not include the input parameter incentives_controllers which is passed "empty" (option::none()) to the pool_token_logic::init_reserve. This means that every reserve will always be initialized with an empty incentive controller that needs to be configured later on.
"Same" events are defined multiple times across modules
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
In Aptos, events with the same names and struct fields that are defined in separate modules will be treated as separate events. This makes it hard to query for the event as the event needs to be queried across all modules it is defined in and the results must be merged. The proper approach is to have the event defined in a single module. Some events that represent a single event in Aave Solidity are defined across several modules in Aave Move.
token_base allows A/V token to de-sync the incentive controllers
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
When the reserve is deployed, the caller provides only one common (empty or not) incentive controller to be used for both the AToken and VariableDebtToken. The set_incentives_controller allows the caller to set a new (empty or not) incentives_controller for the single AToken or VariableDebtToken. This behavior allows the system to de-sync the tokens incentive controller that should be the same given the assumption used during the reserve's initialization. With the current logic, we could end up with: • A/V tokens are configured with different incentive controllers. • One of the two token have the incentive controller configured and the other not.
Side effects of deploying the AToken and VariableDebtToken as FungibleAsset
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Spearbit
Report Date: Jun 2025
Description:
In the current implementation of the Aptos codebase both the AToken and VariableDebtToken are deployed as FungibleAsset. When the user mint AToken or VariableDebtToken, the receiving wallet is immediately frozen (see token_base.move?lines=260,265).
Updating/Fetching the reward's emission admin should not revert when there's no rewards_controller configured
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Periphery
Auditor: Spearbit
Report:
Report Date: Jun 2025
Description:
The rewards_controller attribute stored in the EmissionManagerData struct of the emission_- manager holds the value of the "current" rewards_controller configured. Such value could be not configured yet or simply set to option::none() to state the that there's no not a current reward controller in action. The emission admin of a reward is stored as an item of emission_admins: SmartTable<address, address> in the EmissionManagerData struct is not bound to the value of rewards_controller. The @aave_pool admin user should always be able to configure/update an emission admin for a reward, even if the rewards_controller has not been configured yet. The same should also be true for the getter function relative to the reward's emission admin.
rewards_controller module events are not tracking which rewards_controller_address has emitted them
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Periphery
Auditor: Spearbit
Report:
Report Date: Jun 2025
Description:
The rewards_controller module can be seen as a "factory" of rewards controllers. Almost all the functions take an arbitrary rewards_controller_address address as an input parameter to distinguish which reward controller is being used for the internal function logic.
Aave Core and Aave Reward use the same oracle's module
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Periphery
Auditor: Spearbit
Report:
Report Date: Jun 2025
Description:
With the current implementation of the Aptos codebase, the oracle module maps both the prices of the assets used as Aave Protocol Core reserves and the one used as rewards of the Aave Periphery reward system.
rewards_controller::handle_action should never revert
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Periphery
Auditor: Spearbit
Report:
Report Date: Jun 2025
Description:
The handle_action function of the rewards_controller modules is called by the AToken or VariableDebtToken logic when the user mint/burn/transfer those tokens. Reverting during the execution of the handle_action function means that the above functions (in the AToken or VariableDebtToken context), that are crucial in the Aave Core logic, would break. If the incentives_controller attribute has not been configured (empty) or is misconfigured, the handle_action should just return early without tracking the user rewards and never revert.
Users near MIN_BASE_MAX_CLOSE_FACTOR_THRESHOLD can be fully liquidated by using multi liquidations
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.1-3.3 Core
Auditor: Spearbit
Report: https://github.com/aave/aptos-aave-v3/blob/main/audits/Spearbit Aave Aptos Core V3.1-V3.3 Report.pdf
Report Date: Jun 2025
Description:
Aave 3.3 introduced new minimum position size thresholds that must exist after liquidations if the entire balance cannot be cleared. This is to prevent position sizes of small amounts that are not unprofitable to liquidate, for example, because of gas costs. • The MIN_BASE_MAX_CLOSE_FACTOR_THRESHOLD is currently set to 2000$. • The "dust value" is half of that, set to MIN_LEFTOVER_BASE = 1000$. The rules are as follows: • Full-liquidation: The max close factor is 50% of the user's total debt value (no full liquidation) if-and-only-if HF > 95% AND debt$ >= 2000$ AND collateral$ >= 2000$. Otherwise, the close factor is 100%. • Liquidation failures due to dust position sizes: Liquidation fails if both collateral and debt balances are non-zero after the liquidation and any of the balances is less than 1000$: collateral_left$ > 0 AND debt_left$ > 0 AND (collateral_left$ < 1000$ OR debt_left$ < 1000$).
Minimum position size post-liquidation checks can end up reverting legitimate liquidations
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.1-3.3 Core
Auditor: Spearbit
Report: https://github.com/aave/aptos-aave-v3/blob/main/audits/Spearbit Aave Aptos Core V3.1-V3.3 Report.pdf
Report Date: Jun 2025
Description:
Aave 3.3 introduced new minimum position size thresholds that must exist after liquidations if the entire balance cannot be cleared. This is to prevent position sizes of small amounts that are not unprofitable to liquidate, for example, because of gas costs. • The MIN_BASE_MAX_CLOSE_FACTOR_THRESHOLD is currently set to 2000$. • The "dust value" is half of that, set to MIN_LEFTOVER_BASE = 1000$. The rules are as follows: • Full-liquidation: The max close factor is 50% of the user's total debt value (no full liquidation) if-and-only-if HF > 95% AND debt$ >= 2000$ AND collateral$ >= 2000$. Otherwise, the close factor is 100%. • Liquidation failures due to dust position sizes: Liquidation fails if both collateral and debt balances are non-zero after the liquidation and any of the balances is less than 1000$: collateral_left$ > 0 AND debt_left$ > 0 AND (collateral_left$ < 1000$ OR debt_left$ < 1000$).
AggregatedReserveData misses the virtual_underlying_balance and is_virtual_acc_active data attributes
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.1-3.3 Core
Auditor: Spearbit
Report: https://github.com/aave/aptos-aave-v3/blob/main/audits/Spearbit Aave Aptos Core V3.1-V3.3 Report.pdf
Report Date: Jun 2025
Description:
The AggregatedReserveData struct in ui_pool_data_provider_v3 is missing two attributes that should be returned by the get_reserves_data function. These two values are: • virtual_underlying_balance which represents the underlying balance held in the AToken resource account. • is_virtual_acc_active reserve flag
Improper Event Emission Due to Variable Shadowing
Severity: Low
Ecosystem: Aptos
Protocol: AAVE v3.0.2 Core
Auditor: Certora
Report: https://github.com/aave/aptos-aave-v3/blob/main/audits/Ottersec Aave Aptos V3.1-V3.3 Report.pdf
Report Date: Apr 2025
Description:
The pending_ltv_set variable is shadowed inside the if block, resulting in the emitted event always reporting a zero value instead of the actual LTV .
Hardcoded Dust Threshold in Swap Logic
Severity: Low
Ecosystem: Aptos
Protocol: Hyperionxyz Vaults
Auditor: ExVul
Report Date: Apr 2025
Description:
The threshold 10 used to decide whether to perform another swap (swap_deposit) is hardcoded. This doesn't account for the varying decimal places of different tokens, potentially leaving significant value as dust for some tokens or unnecessarily swapping for others.
Bypassing team_reward Limitation
Severity: Low
Ecosystem: Aptos
Protocol: TokimonsterAI
Auditor: ExVul
Report Date: May 2025
Description:
In the initialize function of TokimonsterRewarder, there is a constraint ensuring team_reward does not exceed 100. However, the set_override_team_rewards_for_token and add_user_reward_recipient functions lack similar limitations. If team_reward is set above 100, extract operations will fail due to insufficient funds, creating a potential vulnerability.
Invalid Address Replacement in replace_user_reward_recipient Function
Severity: Low
Ecosystem: Aptos
Protocol: TokimonsterAI
Auditor: ExVul
Report Date: May 2025
Description:
The replace_user_reward_recipient function in TokimonsterRewarder fails to verify whether old_recipient and recipient are the same. This allows for address - replacement operations that are, in reality, non - operational. Such actions result in unnecessary gas consumption and the generation of invalid event logs.
Incorrect Display of Bridge Info
Severity: Low
Ecosystem: Sui
Protocol: Mango
Auditor: ExVul
Report Date: July 2025
Description:
In the config.move file, the pair_list function constructs a list of pairs by iterating through pair_id using a while loop. However, it fails to account for special pairs that may have been created using the create_special_bridge_pair function, where the specified id can be greater than the current pair_id. As a result, those special pairs are omitted during iteration. Ultimately, this leads to an incomplete BridgeInfo being returned in the bridge_info function of bridge.move.
Existence check problem
Severity: Low
Ecosystem: Sui
Protocol: Mango
Auditor: ExVul
Report Date: July 2025
Description:
In the treasury.move file, the add_treasury_cap function does not check if the same type already exists in treasuries. If so, it will abort. The function directly adds to the ObjectBag without checking if the key already exists, which will cause an abort if the treasury type already exists.
Faulty logic allows duplicate custodian addition
Severity: Low
Ecosystem: Sui
Protocol: Elixir
Auditor: Pashov Audit Group
Report: https://github.com/pashov/audits/blob/master/team/pdf/Elixir-security-review_2025-08-17.pdf
Report Date: Aug 2025
Description:
In deusd_minting.move function add_custodian_address_internal(), the incorrect assertion logic fails to prevent duplicate custodian addresses from being added.
Unavailable view function
Severity: Low
Ecosystem: Sui
Protocol: Elixir
Auditor: Pashov Audit Group
Report: https://github.com/pashov/audits/blob/master/team/pdf/Elixir-security-review_2025-08-17.pdf
Report Date: Aug 2025
Description:
The cooldown_underlying_amount and cooldown_end_time functions take a UserCooldown and return its underlying_amount and cooldown_end fields. However, these two view functions are actually unusable because UserCooldown is a field within SdeUSDManagement, which cannot be directly accessed by external modules. Moreover, the module does not contain any function that returns a reference to UserCooldown. Therefore, these two functions cannot be used in practice.
Soft restriction bypass via token transfers
Severity: Low
Ecosystem: Sui
Protocol: Elixir
Auditor: Pashov Audit Group
Report: https://github.com/pashov/audits/blob/master/team/pdf/Elixir-security-review_2025-08-17.pdf
Report Date: Aug 2025
Description:
In the sdeusd.move function add_to_blacklist() function soft-restricted users are only blocked from direct staking but can receive sdeUSD tokens via transfers, bypassing the restriction entirely.
Cooldown timer reset causes user withdrawal delays
Severity: Low
Ecosystem: Sui
Protocol: Elixir
Auditor: Pashov Audit Group
Report: https://github.com/pashov/audits/blob/master/team/pdf/Elixir-security-review_2025-08-17.pdf
Report Date: Aug 2025
Description:
In deusd_lp_staking.move function unstake() , each unstake operation overwrites the cooldown timestamp for all cooling tokens, not just the newly unstaked amount. If you check this vulnerable code, it resets the timer for ALL cooling tokens.
Cooldown duration changes apply retroactively
Severity: Low
Ecosystem: Sui
Protocol: Elixir
Auditor: Pashov Audit Group
Report: https://github.com/pashov/audits/blob/master/team/pdf/Elixir-security-review_2025-08-17.pdf
Report Date: Aug 2025
Description:
In deusd_lp_staking.move function withdraw() , the cooldown duration is read from current parameters at withdrawal time, not locked when user unstakes. Admin can change cooldown periods mid-stream, affecting users who have already begun cooling down. Let's check this scenario: 1. User unstakes 1000 tokens when cooldown = 30 days. 2. User expects withdrawal on Day 30. 3. Admin updates cooldown to 60 days on Day 20. 4. User tries withdrawing on Day 30 → fails because assert!(current_time >= stake_data.cooldown_start_timestamp + params.cooldown, ECooldownNotOver); now requires 60 days. The root cause is that params.cooldown always reads current global setting, not the duration that was active when the user started cooldown.
Security Levels Lack Flexibility
Severity: Low
Ecosystem: Sui
Protocol: BalancerV2
Auditor: Quantstamp
Report Date: Aug 2025
Description:
The vault implements a three-level security system that provides insufficient granularity for emergency responses. Level 0 allows all operations, level 1 blocks everything, and level 2 blocks borrowing, repaying, and withdrawing while still allowing deposits and liquidations. This design may force administrators to disable critical functions unnecessarily.
pair::set_static_fee_parameters_internal updates volatility_accumulator to the new max value
Severity: Low
Ecosystem: Aptos
Protocol: Magma DEX
Auditor: Three Sigma
Report: https://cdn.sanity.io/files/qoqld077/staging/9566473c444a6cfd99c7a6556fa4857950b41de3.pdf
Report Date: July 2025
Description:
When updating the static fee parameters, we change a lot of variables including max_volatility_accumulator. After setting the new values, we change the volatility_accumulator to the new max_volatility_accumulator value, and we calculate the total_fees that will be accumulated at the max value. and making sure it do not exceeds MAX_TOTAL_FEE variable.
Insufficient vault balance validation in almm_rewarder::update_emission leads to overcommitted rewards and failed user claims
Severity: Low
Ecosystem: Aptos
Protocol: Magma DEX
Auditor: Three Sigma
Report: https://cdn.sanity.io/files/qoqld077/staging/9566473c444a6cfd99c7a6556fa4857950b41de3.pdf
Report Date: July 2025
Description:
The almm_rewarder::update_emission function validates vault balance before updating emission rates but fails to account for unclaimed rewards already promised to users. The function checks total vault balance without subtracting rewards accumulated through both PositionReward.amount_owned and the time-weighted growth calculation, allowing the protocol to overcommit rewards beyond available collateral.
Incorrect value capture order in set_protocol_variable_share leads to misleading event data
Severity: Low
Ecosystem: Aptos
Protocol: Magma DEX
Auditor: Three Sigma
Report: https://cdn.sanity.io/files/qoqld077/staging/9566473c444a6cfd99c7a6556fa4857950b41de3.pdf
Report Date: July 2025
Description:
The almm_pair::set_protocol_variable_share function updates the protocol variable share parameter but captures the old value after the parameter has already been modified. This causes the EventNewProtocolVariableFee event to emit identical values for both old_share and share fields.