Open hats-bug-reporter[bot] opened 8 months ago
_msgSender()
is the caller in the context of the current call. The modifier works correctly.
How is the _msgSender() set?
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
This is exactly what I'm talking about - function _msgSender() internal view virtual returns (address) { return msg.sender; }
What the above means is that the deployer of the contract auto becomes the sender.
However, in the initialize function ownership was transferred.
The msg.sender
of the call is not set at any time, and it is the EOA or contract that has called the external or public function. If Alice calls addRewardController()
then msg.sender
is Alice's address, if Bob calls addRewardController()
then msg.sender
is Bob's address
@bahurum, I disagree with your explanation. Here's why:
Here's the onlyRegistryOwner() modifier:
In the modifier, registry.owner() returns Ownable.owner declared in HATVaultsRegistry.sol. Here's the code:
And looking up Ownable.owner function, it returns _owner. Here's the code:
And the _owner variable is reset in the _transferOwnership function. Here's the code:
Note that by calling the _transferOwnership function, you're resetting from an oldOwner to a new owner.
The first owner in this regard is the deployer of the contract which _msgSender() represents. The new owner is set by calling the _transferOwnership in the initialize function. Here's the code:
Now back to the onlyRegistryOwner modifier, the modifier says if registry.owner() != _msgSender()
- is not the caller of the functions (addRewardController and setVaultDescription), the funtion should revert.
The bug is, ownership has been reset and transferred to a new address in the Initialize function by calling _transferOwnership in the initialize function. This means that owner is no longer the _msgSender(). And registry.owner()
can never be _msgSender() again.
Thus, addRewardController and setVaultDescription will forever revert.
As I said, the bug lies in the use of != _msgSender().
@jellegerbrandy, could you let me know why this report is marked invalid?
This issue is similar to #42 ; similar reasoning applies here.
The test you referred to doesn't cover the vulnerability described in the report.
Github username: @ololade97 Submission hash (on-chain): 0xdb761c8b6418415462587b12cb43b50f568a4bf127b8649979c8a0f28ab931ae Severity: high
Description: Description\ Here's the
onlyRegistryOwner
modifier:modifier onlyRegistryOwner() { if (registry.owner() != _msgSender()) revert OnlyRegistryOwner(); _; }
It means if the registry.owner() is not the deployer address (
_msgSender()
), revert should occur.The vulnerabililty is the use of
_msgSender()
._msgSender
auto set the deployer address as the sender.Whereas, in the initialize function, ownership is transferred to another address.
registry.owner()
shouldn't be checked against_msgSender()
.Functions such as addRewardController, setVaultDescription will always revert and not accessible by anyone.
Attack Scenario\ addRewardController and setVaultDescription functions will not be callable because of the wrongly written
onlyRegistryOwner
modifier.Attachments https://github.com/hats-finance/hats-contracts/blob/0d6ebbde912bc272d9b310140d434ee2aacd36d3/contracts/HATVault.sol#L68-L71
https://github.com/hats-finance/hats-contracts/blob/0d6ebbde912bc272d9b310140d434ee2aacd36d3/contracts/HATVault.sol#L120
https://github.com/hats-finance/hats-contracts/blob/0d6ebbde912bc272d9b310140d434ee2aacd36d3/contracts/HATVault.sol#L133
Wrong use of
_msgSender()
below:modifier onlyRegistryOwner() { if (registry.owner() != _msgSender()) revert OnlyRegistryOwner(); _; }
The vulnerability is in the use of
_msgSender()
in the modifier.msg.sender
should be used instead.modifier onlyRegistryOwner() { if (registry.owner() != msg.sender) revert OnlyRegistryOwner(); _; }