RebateFi Hook

First Flight #53
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: high
Valid

Critical Logic Error in ReFi Token Validation Allows Bypass

Recommended Mitigation

Root + Impact

Description

The _beforeInitialize function contains a critical logic error where it checks key.currency1 twice instead of checking both currency0 and currency1. This allows pools that don't contain the ReFi token to use the hook, completely bypassing the intended validation. The duplicate check on line 117 should be checking key.currency0, but instead checks key.currency1 again, making the validation ineffective.

function _beforeInitialize(address, PoolKey calldata key, uint160) internal view override returns (bytes4) {
if (Currency.unwrap(key.currency1) != ReFi &&
Currency.unwrap(key.currency1) != ReFi) {
revert ReFiNotInPool();
}
return BaseHook.beforeInitialize.selector;
}

Risk

Likelihood:

  • This would likely be exploited within hours or days of deployment. The bug is too obvious and the exploit too profitable to remain unexploited.

Impact:

  • Attackers can deploy the hook on pools that don't contain the ReFi token, potentially manipulating fee structures on arbitrary token pairs and bypassing the entire security model of the protocol. This could lead to unexpected fee applications on unrelated tokens.

POC

function demonstrateBug() public pure returns (bool) {
address ReFi = address(0x123);
address USDC = address(0x456);
address WETH = address(0x789);
// Buggy check (what the code does):
bool buggyCheck = (WETH != ReFi && WETH != ReFi); // true && true = true
// This passes even though USDC (currency0) was never checked!
// Correct check (what it should do):
bool correctCheck = (USDC != ReFi && WETH != ReFi); // Checks BOTH
return buggyCheck; // Returns true, allowing exploit
}

Recommended Mitigation

- remove this code
/// @notice Validates that ReFi token is in the pool before initialization
/// @param key The pool key containing currency pair information
/// @return Function selector for success
function _beforeInitialize(address, PoolKey calldata key, uint160) internal view override returns (bytes4) {
if (Currency.unwrap(key.currency1) != ReFi &&
Currency.unwrap(key.currency1) != ReFi) {
revert ReFiNotInPool();
}
return BaseHook.beforeInitialize.selector;
}
+ add this code
/// @notice Validates that ReFi token is in the pool before initialization
/// @param key The pool key containing currency pair information
/// @return Function selector for success
function _beforeInitialize(address, PoolKey calldata key, uint160) internal view override returns (bytes4) {
if (Currency.unwrap(key.currency1) != ReFi &&
Currency.unwrap(key.currency0)//Change this to currency0 != ReFi) {
revert ReFiNotInPool();
}
return BaseHook.beforeInitialize.selector;
}
Updates

Lead Judging Commences

chaossr Lead Judge 11 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Faulty pool check; only checks currency1 twice, omitting currency0.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!