Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: high
Likelihood: medium

Owner Can Change Price Feeds Without Timelock Enabling Rug Attacks

Author Revealed upon completion

Root + Impact

Description

The protocol allows the owner to instantly change price feed addresses for any token. An honest owner ensures correct Chainlink feeds are used, but a malicious or compromised owner can replace legitimate feeds with malicious contracts that return manipulated prices, enabling theft of all user funds with no warning.

@> function setPriceFeed(address _token, address _priceFeed) external onlyOwner {
_setPriceFeed(_token, _priceFeed);
emit PriceFeedUpdated(_token, _priceFeed);
}

Risk

Likelihood:

  • Owner key compromise happens regularly in DeFi (hot wallet exploits)

  • Malicious insider with owner access

  • Owner decides to rug users

Impact:

  • Owner sets malicious price feed returning fake prices

  • Opens positions at fake favorable prices, stealing protocol funds

  • Liquidates all user positions by manipulating prices

  • Complete loss of all deposited collateral

Proof of Concept

// Attack scenario:
// 1. Attacker compromises owner private key
// 2. User has 100 ETH collateral, 50 ETH debt (healthy 2x position)
// 3. Attacker calls setPriceFeed(ETH, maliciousContract)
// 4. Malicious contract returns ETH price = $1 (instead of $3000)
// 5. User's position now appears underwater (100*$1 < 50*$3000)
// 6. Attacker liquidates user, steals 100 ETH
// 7. Attacker repeats for all users, drains protocol

Recommended Mitigation

+ uint256 public constant TIMELOCK_DELAY = 2 days;
+ mapping(address => uint256) public pendingPriceFeedUpdates;
- function setPriceFeed(address _token, address _priceFeed) external onlyOwner {
+ function queuePriceFeedUpdate(address _token, address _priceFeed) external onlyOwner {
+ require(_priceFeed != address(0), "Invalid price feed");
+ pendingPriceFeedUpdates[_token] = block.timestamp;
+ emit PriceFeedUpdateQueued(_token, _priceFeed, block.timestamp + TIMELOCK_DELAY);
+ }
+
+ function executePriceFeedUpdate(address _token, address _priceFeed) external onlyOwner {
+ require(pendingPriceFeedUpdates[_token] != 0, "Not queued");
+ require(block.timestamp >= pendingPriceFeedUpdates[_token] + TIMELOCK_DELAY, "Timelock active");
+ delete pendingPriceFeedUpdates[_token];
_setPriceFeed(_token, _priceFeed);
emit PriceFeedUpdated(_token, _priceFeed);
}

Support

FAQs

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

Give us feedback!