Lack of Two-Step Ownership Transfer Pattern Creates Risk of Irrevocable Loss of Administrative Control
The contract inherits from OpenZeppelin's standard Ownable.sol, which facilitates ownership transfer in a single transaction (transferOwnership). This one-step process is risky because if the current owner accidentally transfers ownership to an incorrect or inaccessible address (e.g., a typo in an EOA, a smart contract with no function to accept ownership, or an address from a different network), all administrative privileges will be permanently and irrevocably lost. This poses a significant operational risk to the protocol, as critical functions like setAllowedSellToken and withdrawFees would become unusable.
The OrderBook contract relies on an owner to perform critical administrative functions. The ownership is managed by OpenZeppelin's Ownable.sol.
The standard transferOwnership(address newOwner) function in Ownable executes the transfer immediately. There is no confirmation step from the newOwner. This means a simple human error, such as a copy-paste mistake when specifying the newOwner address, can lead to a catastrophic outcome. If the ownership is transferred to an address that cannot be controlled, there is no recovery mechanism.
Scenario of Failure:
The current owner intends to transfer ownership to a new multi-sig wallet at address 0xabc...def.
They accidentally paste an incorrect address, 0xabc...dff, which is either a typo, an address they do not control, or a contract without ownership capabilities.
They call transferOwnership("0xabc...dff").
The transaction succeeds, and the ownership is instantly transferred.
All administrative functions are now permanently locked, as no one can sign transactions from the incorrect newOwner address.
This vulnerability creates a single point of failure around the ownership transfer process. The impact of a mistake is irreversible and severe:
Permanent Loss of Control: All functions guarded by the onlyOwner modifier, including setAllowedSellToken, emergencyWithdrawERC20, and withdrawFees, become permanently inaccessible.
Frozen Protocol Fees: The owner will be unable to withdraw accumulated protocol fees, leading to a direct loss of revenue.
Inability to Manage Tokens: The owner will be unable to add support for new tokens or delist problematic ones, hindering the protocol's adaptability and security response.
Low. While the action of transferring ownership is infrequent, the potential for human error is always present, and the consequences are permanent.
A conceptual PoC is more appropriate here as this is a protocol design issue rather than a runtime bug. The vulnerability lies in the transferOwnership function inherited from Ownable.sol.
Action: The current owner calls book.transferOwnership(incorrect_address).
State Change: The _owner variable in the Ownable contract is immediately set to incorrect_address.
Result: Any subsequent calls to onlyOwner functions (e.g., book.withdrawFees(owner)) will fail for the original owner. If incorrect_address is uncontrollable, these functions are lost to everyone.
It is strongly recommended to implement a two-step ownership transfer pattern. This ensures the recipient address is valid, accessible, and ready to accept the new role before the final transfer occurs. OpenZeppelin provides a secure, drop-in replacement with Ownable2Step.sol.
Migration Steps:
Replace the import of Ownable.sol with Ownable2Step.sol.
Change the contract inheritance from is Ownable to is Ownable2Step.
This change replaces the risky one-step transferOwnership with a safer two-step process:
transferOwnership(newOwner): The current owner nominates a pendingOwner.
acceptOwnership(): The nominated pendingOwner must call this function to confirm and finalize the transfer.
This prevents ownership from being lost due to simple mistakes.
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.