Submitted by TheSchnilch, also found by ret2basic
https://github.com/code-423n4/2025-04-cabal/blob/5b5f92ab4f95e5f9f405bbfa252860472d164705/sources/cabal.move#L1051-L1054
When a user unstakes LP tokens, the corresponding shares (Cabal tokens) are burned. However, the actual undelegation from the validator will occur only after a delay of up to 3 days. During this period, the shares are already burned, but the underlying tokens are still included in shares-to-token conversions.
This is a problem because, in process_lp_unstake, the amount of tokens to unbond is calculated as follows:
https://github.com/code-423n4/2025-04-cabal/blob/5b5f92ab4f95e5f9f405bbfa252860472d164705/sources/cabal.move#L1051-L1054
The lp_amount is calculated based on the amount of tokens actually staked on the validator. This includes tokens that are pending to be undelegated (unstaked_pending_amounts), for which the Cabal tokens have already been burned.
This means that the unbonding_amount is also calculated incorrectly because the lp_amount is too high. As a result, the unbonding_amount will also be too high, and the unstaker will receive too many tokens that are actually belonging to other users.
Since the Cabal tokens a user receives are also calculated this way in process_lp_stake, users will receive too few shares when there are pending undelegations. As a result, they will have fewer tokens after the next batch_undelegate_pending_lps:
https://github.com/code-423n4/2025-04-cabal/blob/5b5f92ab4f95e5f9f405bbfa252860472d164705/sources/cabal.move#L946-L953
Because users receive too many tokens that actually belong to other users, and since this issue occurs during normal unstaking and staking, it is high severity.
The unstaked_pending_amounts should be subtracted from the lp_amount to correctly account for the pending tokens to be undelegated, for which the Cabal tokens have already been burned.
You can also add debug::print(&unbonding_amount); to line 1334 in cabal.move to verify that 75 ULP tokens are being unstaked instead of 50.
To run the POC, paste it into the file tests/core_staking_test.move and run the command initiad move test -f test_poc
