The update_price
function in the contract allows the PRICE_PARAMETERS_VERIFIER
role to submit price updates without restriction on frequency. This means an attacker with this role can spam multiple updates in a single block, effectively preventing other valid updates from being processed in a timely manner. This creates a Denial of Service (DoS) vulnerability, which can lead to disruption in price-dependent calculations
Affected Functions:
function update_price(uint256 new_price) external onlyRole(PRICE_PARAMETERS_VERIFIER) {
price = new_price;
emit PriceUpdated(new_price);
The function does not enforce any rate-limiting mechanism (e.g., time-based restrictions or cooldowns).
A privileged attacker can submit multiple updates in a single block, making it difficult for others to submit their own updates.
This could be used maliciously to block legitimate updates or manipulate price-based calculations in the protocol.
An attacker with PRICE_PARAMETERS_VERIFIER
role calls update_price(new_price)
multiple times within a single block.
This floods the mempool and prevents other legitimate transactions from being mined efficiently.
If external protocols rely on this price, they might be fed misleading or stale data due to this disruption
Funds are indirectly at risk: If other smart contracts rely on this price feed for calculations (e.g., lending, liquidation, or swaps), incorrect or delayed price updates could lead to financial losses.
Protocol availability is disrupted: The price mechanism can be monopolized by a single entity, preventing fair updates.
Potential market manipulation: Attackers could strategically spam price updates to control external protocol reactions.
Manual Review of the contract code.
Hardhat/Foundry (optional) for testing spam transactions.
Enforce a cooldown period between successive updates:
mapping(address => uint256) public lastUpdateTime;
uint256 public updateCooldown = 1 minutes;
function update_price(uint256 new_price) external onlyRole(PRICE_PARAMETERS_VERIFIER) {
require(block.timestamp >= lastUpdateTime[msg.sender] + updateCooldown, "Cooldown active");
lastUpdateTime[msg.sender] = block.timestamp;
price = new_price;
emit PriceUpdated(new_price);
}
Restrict how many times an address can update the price in a single block:
mapping(uint256 => mapping(address => bool)) public hasUpdated;
function update_price(uint256 new_price) external onlyRole(PRICE_PARAMETERS_VERIFIER) {
require(!hasUpdated[block.number][msg.sender], "Only one update per block");
hasUpdated[block.number][msg.sender] = true;
price = new_price;
emit PriceUpdated(new_price);
}
By implementing these fixes, the risk of denial-of-service attacks is mitigated, ensuring fair price updates for all participants.
- Per [codehawks documentation](https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity#findings-that-may-be-invalid) - Parameter change is executed via the Dao per docs > Also, it is worth noting that the oracle is controlled by a DAO and its parameters can be changed by a vote.
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.