Skip to content

Latest commit

 

History

History
82 lines (55 loc) · 3.13 KB

077.md

File metadata and controls

82 lines (55 loc) · 3.13 KB

Slow Misty Iguana

High

Sending coins to feeCollector can cause a panic in BeginBlocker().

Summary

Crafting a malicious token and sending it to feeCollector can trigger a panic in BeginBlocker().

Root Cause

HandleCoinsInFeeCollector will obtain all coins on the feeCollector address, not a specific coin.

Internal pre-conditions

External pre-conditions

Attack Path

  1. 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.
  2. The attacker sends the malicious tokens to the feeCollector address.
  3. When accumulateBTCStakingReward() is called in BeginBlocker, it triggers a panic.

Impact

This could cause a panic in BeginBlocker(), leading to a complete halt of the chain.

PoC

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.

Mitigation

Do not process all tokens under the feeCollector address; only handle tokens where the BondDenom is "ubbn".