Summary
The contract allows the owner to arbitrarily set buyFee and sellFee to any uint24 value. These values are later combined with Uniswap’s fee override flag using bitwise OR:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L165-L173
return (
BaseHook.beforeSwap.selector,
BeforeSwapDeltaLibrary.ZERO_DELTA,
fee | LPFeeLibrary.OVERRIDE_FEE_FLAG
);
Uniswap V4 expects fee values to remain within a specific bit range. The fee override flag occupies the most significant bit of the 24-bit fee field. If the owner sets a fee that already uses that bit (or uses overly large values), the resulting encoded fee becomes invalid. The pool manager may interpret the fee incorrectly or revert internally, effectively preventing swaps.
This gives the owner the ability to unintentionally or intentionally brick swaps through misconfiguration. Since this hook advertises a fee-override mechanism and will likely be used with UI-controlled dynamic fees, misconfiguration is realistic.
Technical Details
Fees are stored as uint24:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L41-L42
uint24 public buyFee;
uint24 public sellFee;
The owner can set any values up to 16,777,215:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L99-L113
function ChangeFee(...) external onlyOwner {
if (_isBuyFee) buyFee = _buyFee;
if (_isSellFee) sellFee = _sellFee;
}
No range check is applied.
In _beforeSwap the fee is OR-ed with the override flag:
https://github.com/CodeHawks-Contests/2025-11-rebatefi-hook/blob/main/src/RebateFiHook.sol#L165-L173
fee | LPFeeLibrary.OVERRIDE_FEE_FLAG
Uniswap defines fee encoding so that the override flag sits on the highest bit. Valid fee values must not collide with it. If the owner sets any fee where the top bit is already 1 (for example anything above approximately 2^23), the final encoded fee becomes invalid.
As a result, the pool manager may revert or interpret the fee as corrupted. Swap calls will fail even though the pool itself is otherwise valid.
This constitutes a centralized DoS vector for any pool using the hook.
Example Scenario
A frontend lets the admin update fees.
Admin mistakenly sets sellFee = 10000000.
This value overlaps with the override-flag bit.
Next _beforeSwap produces an invalid encoded fee.
Pool manager fails to process the swap and reverts.
All swaps through this hook are now blocked until the admin corrects the mistake.
There is no on-chain safeguard preventing this.
Why Impact Is High
The hook overrides every swap in the pool.
A malformed fee value breaks the encoded fee, blocking swapping entirely.
The system depends on dynamic fee override, making the correct encoding essential.
A single bad admin change is enough to stop trading.
Even though the threat originates from configuration rather than an external attacker, it is still a harmful vulnerability because a misconfigured upgrade or UI can cause a live pool to stop functioning.
Recommended Fix
Add explicit range checks to ensure fees remain inside the valid, non-overlapping portion of the 24-bit fee space.
For example:
uint24 MAX_UNISWAP_FEE = 1_000_000; // or the appropriate upper safe bound
require(_buyFee < MAX_UNISWAP_FEE, "Fee too large");
require(_sellFee < MAX_UNISWAP_FEE, "Fee too large");
Alternatively, mask out the override flag:
fee = fee & ~LPFeeLibrary.OVERRIDE_FEE_FLAG;
This ensures the final encoded fee remains valid and cannot break swap execution.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.