Ammplify — disclosed vulnerability reports and payouts
Every publicly disclosed and closed bug bounty report we hold for Ammplify, with our own summary of each finding and a link to the original disclosure.
- Reports indexed
- 33
- Total paid
- $0
- Critical
- 0
- Largest payout
- $0
This page collects the 33 closed, publicly disclosed Ammplify reports indexed on CoinBuggie. Nothing here is active or unpatched — every entry was published by the programme or the researcher after remediation.
The findings concentrate in Reentrancy, Logic error, Price manipulation, Integer overflow / underflow, across EVM-Solidity. Reading a single protocol end to end is the fastest way to see which assumptions its codebase repeatedly gets wrong, which is usually a better predictor of where the next finding lives than the category alone.
Use the vulnerability class links below to compare these findings against the same bug class in other protocols.
What reviewers look for
- Reentrancy findings disclosed against Ammplify
- Logic error findings disclosed against Ammplify
- Price manipulation findings disclosed against Ammplify
- Integer overflow / underflow findings disclosed against Ammplify
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
Ammplify: All taker collateral and collected fees can be stolen by re-entering via `RFTLib.settle` to manipulate uniswap spot price when adding Maker liquidity
Ammplify's maker liquidity functions compute and charge a user token amounts for a new or adjusted Uniswap v3 position, but never verify the amounts the contract actually spends when the pool mints that liquidity. Because RFTLib.settle invokes a user-supplied callback before PoolWalker settles and mints the position, an attacker can re-enter and move the pool spot price mid-transaction, causing the subsequent mint to consume far more of the higher-value token from the contract than was charged. After restoring the price, the attacker pockets the difference from the contract's own balances, which include all taker collateral and unclaimed pool fees. The documented path drains 90-99% of the contract's token balances in a single transaction and nets roughly $8,889 after 0.3% Uniswap fees.
Ammplify: Attackers can drain the protocol tokens
Ammplify's Maker.newMaker() accepts a caller-supplied pool address without verifying it is a genuine Uniswap V3 pool created by the official factory. Because every pool address is written into the POOL_GUARD_SLOT before its mint() is invoked, an attacker can substitute their own contract that returns arbitrary owed amounts from the mint callback. The legitimate uniswapV3MintCallback then transfers the maker's full token balances to the attacker on those amounts, draining collected fees, JIT penalties, and potentially principal liquidity not yet minted. The protocol team acknowledged the issue and fixed it in PR #43 by validating the pool against the Uniswap V3 factory.
Ammplify: Accrued maker fees not yet compounded can be stolen by manipulating uniswap pool spot price to reduce fees equivalent liquidity and liquidity share price on maker liquidity deposit
Ammplify, a Uniswap V3-based AMM, computes an "equivalent liquidity" figure from accrued-but-uncompounded maker fees by dividing fee value by per-unit-liquidity value at the live pool spot price (slot0). Because slot0 is manipulable within a single transaction, an attacker can drive the price to a point that collapses the equivalent-liquidity denominator, deposit maker liquidity at a deflated share price to receive extra shares, then restore the price and withdraw at the true share price — siphoning a large share of other makers' unbundled fees. The report's worked example shows ~387 token0 net profit against 977 token0 of fees with only ~2% manipulation cost, and the attack is repeatable and scalable.
Ammplify: `Maker.adjustMaker` always reverts when trying to reduce maker liquidity while current price is below position range
Ammplify's Maker.adjustMaker enforces that both computed token deltas share the same sign when reducing a maker position, but one legitimate combination (xBalance < 0 with yBalance == 0) is misrouted into a branch that requires yBalance < 0 and therefore reverts. This combination arises exactly when the current pool price sits below the position range, so the position holds only token x and zero token y. As a result the user cannot reduce the position and their funds stay trapped in the contract, potentially permanently if the price never recovers above the lower tick — or at a real cost, since forcing the price back into range to enable reduction is expensive. The protocol relaxed the require condition to yBalance <= 0 in a fix committed to the Ammplify repository.
Ammplify: NFTManager `burnAsset` always triggers JIT penalty on removal
Ammplify's NFTManager.burnAsset() closes a maker position by first calling MakerFacet.collectFees(), which writes the current block timestamp into the asset's stored timestamp, and only then calls removeMaker(). Because removeMaker() computes the position's held duration from that just-reset timestamp, the duration always evaluates to zero. When the JIT mechanism is configured with a non-zero penalty, FeeLib.applyJITPenalties then applies an unjustified haircut to the closing user's withdrawn principal even for long-held positions. The fix applied by the team stops updating the timestamp inside collectFees() so removeMaker() sees the true original open time.
Ammplify: transferVaultBalance function is unusable and mistransfers user's funds due to hardcoded asset ID
Ammplify's admin vault-migration function, AdminFacet.transferVaultBalance, hardcodes TAKER_VAULT_ID (80085) and forwards it to VaultLib.transfer as the userId for both the source withdrawal and destination deposit. Because taker and view balances are keyed by each position's own assetId rather than any fixed id, the migration almost always targets an empty account, so the withdraw finds no shares and the entire call reverts, leaving the admin rotation tool unusable. Since assetIds are assigned sequentially, a user position will eventually collide with value 80085, at which point the same administrative call would silently move that user's funds between vaults without consent. The finding was upheld as medium and fixed by the protocol team via PR #37, with remediation recommending removal of the function, reliance on VaultLib.hotSwap lazy migration, and reserving id 80085 so it can never be handed to a user.
All reports in this group
- Ammplify: JIT penalty on fresh fees can be bypassedLogic error$0
- Ammplify: `Maker.collectFees` re-targets liquidity to original amount even if the maker position was adjusted, causing unexpected position change when the user expected to collect fees only.Logic error$0
- Ammplify: NFTManager will break NFT metadata for users as tokenURI() will revertLogic error$0
- Ammplify: Missing width scaling in FeeWalker.up (non-visited) undercredits compounding maker feesLogic error$0
- Ammplify: Borrow fee uses APY as per-second rate, causing extreme overchargingInteger overflow/underflow$0
- Ammplify: DoS of pool if uniswapV3MintCallback's tokenAmountOwed is 0 for a `Revert on Zero Value Transfers` token.Logic error$0
- Ammplify: An attacker can block a user from opening new Maker/Taker positions by “donating” 16 unwanted Maker assets, saturating their asset quotaLogic error$0
- Ammplify: Uncollected fees from user's NFT position are stuck in `NFTManager` if `NFTManager.decomposeAndMint` function is usedLogic error$0
- Ammplify: Some legitimate `UniV3Decomposer` decompose attempts will always revert due to incorrect liquidity offset calculationLogic error$0
- Ammplify: incompatible library used for Fee on Transfer tokensLogic error$0
- Ammplify: Utilization Ratio Overflow Due to Incorrecte uint64 CastInteger overflow/underflow$0
- Ammplify: Incorrect inside fees calculation for uninitialized uniswap ticks causes positions funds being stuck in the contract and allows to steal all taker collateral and collected feesLogic error$0
- Ammplify: X/Y mix-up in ViewWalker.down will underreport X fees and block taker closesLogic error$0
- Ammplify: Shift-Overflow in getEquivalentLiq Inflates LP SharesInteger overflow/underflow$0
- Ammplify: Liquidity borrowed from or repaid to parent nodes is not always minted or burned in the uniswap pool, breaking up accounting and allowing to steal all protocol fundsLogic error$0
- Ammplify: `UniV3Decomposer` will always revert due to incorrect `RFTPayer` support and lack of token approvals to `MakerFacet`Logic error$0
- Ammplify: Takers pay significantly higher fees than expected due to borrow amounts being split across segmentsLogic error$0
- Ammplify: Makers can permanently lock JIT penalty revenue from the protocol treasuryLogic error$0
- Ammplify: adjustMaker ignores recipient parameter when removing liquidityLogic error$0
- Ammplify: `View::queryAssetBalances` does not account for JIT penaltiesLogic error$0
- Ammplify: Mismatch in actual pool's liquidity and pool node's liquidity infomation because of wrong `route` in `PoolWalker.settle`Logic error$0
- Ammplify: Pending Owner cannot accept ownership because of wrong implementation of `transferOwnership` and `acceptOwnership` functionsLogic error$0
- Ammplify: `ViewFacet.queryAssetBalances` doesn't unclude uncollected uniswap fees for compounded maker positionLogic error$0
- Ammplify: User can lose all funds when creating or increasing compounded Maker position due to share inflation first deposit attack in any segment of the user's rangeInteger overflow/underflow$0
- Ammplify: Wide cross-zero ranges revert (InvertedRange) due to sign-loss in tick→index and no wrap supportLogic error$0
- Ammplify: Can't remove compounding maker asset if any visit node in route has only liquidity for itLogic error$0
- Ammplify: Takers can pay significantly less fees with makers losing these amounts due to `subtreeBorrowedX` and `subtreeBorrowedY` being node's values instead of subtree'sLogic error$0