Stratax Contracts

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

Missing Two-Step Ownership Transfer Can Permanently Lock All User Positions

Author Revealed upon completion

Description

  • The Stratax protocol uses an owner-controlled access pattern where only the contract owner can create, manage, and close leveraged positions. The owner has exclusive control over critical functions like creating positions, unwinding positions, and recovering tokens.

  • The transferOwnership() function performs an immediate, single-step ownership transfer without requiring the new owner to accept the transfer. If the owner accidentally transfers ownership to an incorrect address (due to a typo, clipboard hijack, or wrong network address), all user positions become permanently inaccessible with no possibility of recovery.

// File: Stratax.sol, Lines 290-293
function transferOwnership(address _newOwner) external onlyOwner {
require(_newOwner != address(0), "Invalid address");
@> owner = _newOwner; // ❌ Immediate transfer with no confirmation
}

Risk

Likelihood: Low

  • Human error during ownership transfer is common - copying wrong addresses from clipboard, typos in manual entry, or confusion between different network addresses

  • No mechanism exists to verify the new owner can actually access the address before transfer completes

  • Contract upgrades, wallet migrations, or organizational handoffs increase the probability of transfer to wrong address

Impact: Critical

  • Complete loss of access to all protocol functions - no one can create, unwind, or manage any positions

  • All user funds locked forever in leveraged positions with no way to close them or recover collateral

  • No emergency recovery mechanism exists - the contract becomes permanently non-functional

  • Protocol must be completely redeployed, losing all existing positions and user funds

Proof of Concept

// test/unit/VulnerabilityOwnership.t.sol
function test_OwnershipTransferPermanentlyLocksContract() public {
// Setup: Owner has active leveraged position with user funds
address currentOwner = stratax.owner();
// Owner intends to transfer to 0x1234...5678
address intendedNewOwner = address(0x123456789);
// But makes a typo and sends to 0x1234...5679
address wrongAddress = address(0x123456780); // One digit different!
vm.prank(currentOwner);
stratax.transferOwnership(wrongAddress);
// Ownership is immediately transferred
assertEq(stratax.owner(), wrongAddress);
// Original owner loses all access
vm.prank(currentOwner);
vm.expectRevert("Not owner");
stratax.setFlashLoanFee(10);
// Wrong address has no private key - cannot do anything
// All positions are now PERMANENTLY LOCKED
// Cannot create positions
vm.prank(wrongAddress);
vm.expectRevert(); // Wrong address has no private key
// Cannot unwind positions - user funds stuck
// Cannot recover tokens
// Cannot transfer to correct address
// Result: Complete protocol failure, all funds locked forever
}

Recommended Mitigation

Implement a two-step ownership transfer pattern where the new owner must explicitly accept ownership:

+ address public pendingOwner;
+
+ event OwnershipTransferInitiated(address indexed previousOwner, address indexed newOwner);
+ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function transferOwnership(address _newOwner) external onlyOwner {
require(_newOwner != address(0), "Invalid address");
- owner = _newOwner;
+ pendingOwner = _newOwner;
+ emit OwnershipTransferInitiated(owner, _newOwner);
}
+ function acceptOwnership() external {
+ require(msg.sender == pendingOwner, "Not pending owner");
+ address oldOwner = owner;
+ owner = pendingOwner;
+ pendingOwner = address(0);
+ emit OwnershipTransferred(oldOwner, owner);
+ }

This ensures:

  1. Transfer is initiated by current owner

  2. New owner must explicitly accept (proves they control the address)

  3. If wrong address provided, original owner retains control

  4. Only completes when new owner confirms

Support

FAQs

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

Give us feedback!