Slow Misty Iguana
High
Crafting a malicious token and sending it to feeCollector can trigger a panic in BeginBlocker().
HandleCoinsInFeeCollector will obtain all coins on the feeCollector address, not a specific coin.
- The attacker creates malicious tokens, for example, by setting the incentive address as a blacklist or restricting the destination address to only feeCollector, with all other addresses blacklisted.
- The attacker sends the malicious tokens to the feeCollector address.
- When
accumulateBTCStakingReward()
is called inBeginBlocker
, it triggers a panic.
This could cause a panic in BeginBlocker()
, leading to a complete halt of the chain.
https://github.com/sherlock-audit/2024-12-babylon/blob/main/babylon/x/incentive/keeper/intercept_fee_collector.go#L20 https://github.com/sherlock-audit/2024-12-babylon/blob/main/babylon/x/incentive/keeper/btc_staking_gauge.go#L65
func (k Keeper) HandleCoinsInFeeCollector(ctx context.Context) {
params := k.GetParams(ctx)
// find the fee collector account
feeCollector := k.accountKeeper.GetModuleAccount(ctx, k.feeCollectorName)
// get all balances in the fee collector account,
// where the balance includes minted tokens in the previous block
-> feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress())
// don't intercept if there is no fee in fee collector account
if !feesCollectedInt.IsAllPositive() {
return
}
// record BTC staking gauge for the current height, and transfer corresponding amount
// from fee collector account to incentive module account
// TODO: maybe we should not transfer reward to BTC staking gauge before BTC staking is activated
// this is tricky to implement since finality module will depend on incentive and incentive cannot
// depend on finality module due to cyclic dependency
btcStakingPortion := params.BTCStakingPortion()
btcStakingReward := types.GetCoinsPortion(feesCollectedInt, btcStakingPortion)
-> k.accumulateBTCStakingReward(ctx, btcStakingReward)
}
func (k Keeper) accumulateBTCStakingReward(ctx context.Context, btcStakingReward sdk.Coins) {
// update BTC staking gauge
height := uint64(sdk.UnwrapSDKContext(ctx).HeaderInfo().Height)
gauge := types.NewGauge(btcStakingReward...)
k.SetBTCStakingGauge(ctx, height, gauge)
// transfer the BTC staking reward from fee collector account to incentive module account
-> err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, types.ModuleName, btcStakingReward)
if err != nil {
// this can only be programming error and is unrecoverable
-> panic(err)
}
}
As observed, when malicious tokens are sent to feeCollector
, these tokens are also distributed as rewards to the incentive module account. Since the incentive module account is blacklisted, the SendCoinsFromModuleToModule
function returns an error, ultimately causing a panic.
Do not process all tokens under the feeCollector
address; only handle tokens where the BondDenom
is "ubbn".