While reviewing Hyperlane's smart contract codebase, I identified a critical vulnerability in their rate-limiting implementation that could enable attackers to completely shut down cross-chain token transfers and message verification with minimal effort and cost.
Hyperlane is a permissionless interoperability layer that enables secure cross-chain communication. It uses various security mechanisms, including rate limiting, to prevent abuse and ensure system stability. However, a fundamental flaw in their rate-limiting implementation creates a significant vulnerability.
The issue lies in Hyperlane's RateLimited
contract, specifically in the validateAndConsumeFilledLevel()
function. This function implements a token bucket algorithm for rate limiting, but is marked as public
without any access control:
function validateAndConsumeFilledLevel(
uint256 _consumedAmount
) public returns (uint256) {
uint256 adjustedFilledLevel = calculateCurrentLevel();
require(_consumedAmount <= adjustedFilledLevel, "RateLimitExceeded");
// Reduce the filledLevel and update lastUpdated
uint256 _filledLevel = adjustedFilledLevel - _consumedAmount;
filledLevel = _filledLevel;
lastUpdated = block.timestamp;
emit ConsumedFilledLevel(filledLevel, lastUpdated);
return _filledLevel;
}
The Problem: Anyone can call this function directly and consume the entire available rate limit capacity, effectively performing a denial-of-service attack.
However, the contracts that inherited this function never overrode it or added any proper access controls.
This vulnerability affects two critical components:
Impact: Prevents legitimate token transfers from being dispatched
Duration: Up to 1 day (the DURATION constant for rate limit refill)
Cost to Attacker: Minimal gas fees
Impact: Prevents legitimate message verification
Duration: Up to 1 day until the rate limit naturally refills
Repeatability: The Attack can be performed continuously
Here's how an attacker could exploit this vulnerability:
Monitor the Rate Limit: Call calculateCurrentLevel()
to check available capacity
Exhaust the Limit: Call validateAndConsumeFilledLevel()
With the full available amount
Repeat: Continue the attack as the rate limit refills to maintain persistent DoS
// Attack demonstration
uint256 availableCapacity = rateLimitedHook.calculateCurrentLevel();
rateLimitedHook.validateAndConsumeFilledLevel(availableCapacity);
// Now filledLevel = 0, blocking all legitimate transfers
This vulnerability could enable attackers to:
Halt Cross-Chain Operations: Block all token transfers between chains for extended periods
Disrupt Protocol Operations: Prevent message verification, breaking core functionality
Economic Damage: Force users to wait or pay premium gas prices to compete
Reputation Risk: Damages user trust in the protocol's reliability
Competitive Advantage: Competitors could weaponize this to disrupt Hyperlane's operations
The Hyperlane team resolved the issue by implementing proper access control measures.
This vulnerability highlights several important security principles:
Principle of Least Privilege: Functions should have the minimum necessary visibility
Access Control by Design: Critical functions must implement proper authorization checks
CVSS Score: Likely 8.5+ (High)
Defense in Depth: Rate limiting should be combined with other security mechanisms
Thorough Testing: Security tests should include adversarial scenarios
This vulnerability was responsibly disclosed to the Hyperlane team, allowing them to address the issue before public disclosure. Since Immunefi's bug bounty program does not cover the problem, no bounty payout has been made.
Developers (or) integrators of Hyperlane should exercise additional caution while using these contracts, which are not adequately covered under the Bug Bounty program, which may contain vulnerabilities.