With an assertion very similar to the Price Deviation Assertion, this attack could have been prevented.
The example assertion below could with very few changes have caught the large price deviations in the attack and prevented the transaction.
Copy
Ask AI
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;import {Assertion} from "credible-std/Assertion.sol";import {PhEvm} from "credible-std/PhEvm.sol";contract IntraTxOracleDeviationAssertion is Assertion { // Maximum allowed price deviation (10% by default) uint256 public constant MAX_DEVIATION_PERCENTAGE = 10; function triggers() external view override { // Register trigger for oracle price update calls registerCallTrigger(this.assertOracleDeviation.selector, IOracle.updatePrice.selector); } // Check that price updates don't deviate more than the allowed percentage // from the initial price at any point during the transaction function assertOracleDeviation() external { // Get the assertion adopter address IOracle adopter = IOracle(ph.getAssertionAdopter()); // Start with a simple check comparing pre and post state ph.forkPreTx(); uint256 prePrice = adopter.price(); // Calculate allowed deviation thresholds (10% by default) uint256 maxAllowedPrice = (prePrice * (100 + MAX_DEVIATION_PERCENTAGE)) / 100; uint256 minAllowedPrice = (prePrice * (100 - MAX_DEVIATION_PERCENTAGE)) / 100; // First check post-state price ph.forkPostTx(); uint256 postPrice = adopter.price(); // Verify post-state price is within allowed deviation from initial price require( postPrice >= minAllowedPrice && postPrice <= maxAllowedPrice, "Oracle post-state price deviation exceeds threshold" ); // Get all price update calls in this transaction // Since this assertion is triggered by updatePrice calls, we know there's at least one PhEvm.CallInputs[] memory priceUpdates = ph.getCallInputs(address(adopter), adopter.updatePrice.selector); // Check each price update to ensure none deviate more than allowed from initial price for (uint256 i = 0; i < priceUpdates.length; i++) { ph.forkPostCall(priceUpdates[i].id); // Call the price function at the given frame in the call stack uint256 updatedPrice = adopter.price(); // Verify each update is within allowed deviation from initial pre-state price require( updatedPrice >= minAllowedPrice && updatedPrice <= maxAllowedPrice, "Oracle intra-tx price deviation exceeds threshold" ); } }}interface IOracle { function updatePrice(uint256 price) external; function price() external view returns (uint256);}
Specifically, the assertion could have been configured to:
Trigger on all calls to the setPrices function in the KiloPriceFeed contract
Enforcing a maximum price deviation of 5% per update
Reverting if the price deviation exceeds this threshold
This would have prevented the attack in two ways:
When the attacker tried to set ETH price to 100(fromthethen2000), the assertion would have detected this ~95% deviation and reverted the transaction
When they later tried to set the price to $10,000, the assertion would have again detected this extreme deviation and reverted
If this was all done in a single transaction, the assertion would have caught the large deviation and reverted the entire transaction
Note: In a real implementation, this assertion should be:
Run for each token in the protocol
Consider token-specific deviation thresholds
Handle multiple price updates in a single transaction
The root cause of the vulnerability was the MinimalForwarder’s lack of access controls. A simple assertion could have prevented this by ensuring the MinimalForwarder is only called by authorized addresses in the expected call chain (Keeper → PositionKeeper → MinimalForwarder):
Trigger: Register for all calls to MinimalForwarder.execute()
Assertion:
Maintain a whitelist of authorized callers (specifically the PositionKeeper)
Verify the caller is in the whitelist
Revert if unauthorized
This simple assertion would have prevented the attack by ensuring that only the PositionKeeper could trigger price updates through the MinimalForwarder. While fixing the access control in the contract itself would be the better solution, this assertion could have served as a safety net to catch unauthorized access attempts.