An attacker can create invalid positions to inflate a pool #59
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
🤖_02_group
AI based duplicate group recommendation
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/code-423n4/2024-08-superposition/blob/4528c9d2dbe1550d2660dac903a8246076044905/pkg/seawater/src/pool.rs#L75
Vulnerability details
Impact
It is possible to inflate a pool by creating a position with an invalid, inverted tick range. This can be abused to artificially change the pool price to the attacker's advantage.
Proof of Concept
It's possible to create a position that has a low tick higher than the low tick as there isn't a check to ensure so:
https://github.com/code-423n4/2024-08-superposition/blob/4528c9d2dbe1550d2660dac903a8246076044905/pkg/seawater/src/pool.rs#L75
An attacker can abuse this by creating positions that have inverted ticks, which doesn't make sense as it breaks the Uniswap math.
A potential scenario is that this could be abused to inflate the pool by only sending token0, as this branch will always be triggered regardless of the current tick.
https://github.com/code-423n4/2024-08-superposition/blob/4528c9d2dbe1550d2660dac903a8246076044905/pkg/seawater/src/pool.rs#L172-L193
As a result, this can be leveraged to influence the pool price to the attacker's advantage.
Run the following POC in
pkg/seawater/tests/pools.rs
:Tools Used
Manual Review
Recommended Mitigation Steps
Consider adding the following check:
pub fn create_position(&mut self, id: U256, low: i32, up: i32) -> Result<(), Revert> { assert_or!(self.enabled.get(), Error::PoolDisabled); let spacing = self.tick_spacing.get().sys() as i32; assert_or!(low % spacing == 0, Error::InvalidTickSpacing); assert_or!(up % spacing == 0, Error::InvalidTickSpacing); let spacing: u8 = spacing.try_into().map_err(|_| Error::InvalidTickSpacing)?; let min_tick = tick_math::get_min_tick(spacing); let max_tick = tick_math::get_max_tick(spacing); assert_or!(low >= min_tick && low <= max_tick, Error::InvalidTick); assert_or!(up >= min_tick && up <= max_tick, Error::InvalidTick); + assert_or!(low < up, Error::InvalidTick); self.positions.new(id, low, up); Ok(()) }
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: