The PasswordStore
contract assumes that only the owner can set the password. The setPassword()
function modifies the s_password
storage variable, where the password is set, but doesn't include access control meaning that anyone, including a malicious actor, can reset the owner's password.
This vulnerability exists in the PasswordStore::setPassword
function in the PasswordStore.sol
file starting on line 26.
The setPassword()
function includes no access controls meaning that anyone can call it and modify the password:
To restrict who can modify the password, there needs to be a check that the function caller, the msg.sender
, is the owner of the contract.
A possible potential use case for this contract is that the owner, the address stored in the storage variable s_owner
, wants to use the contract as a password manager. If someone else can modify the password then the contract will not return the password they intended to store. This negates the intended use of the contract.
Since anyone, inluding malicious actors, can set the password, this opens up to the possibility that, depending on the context, these unsantisied and potentially malicious strings could be dangerous.
As per the following NatSpec comment: This function allows only the owner to set a new password
, only the owner being able to set the password is the core assumtion, and functionality that does not hold, this is a high severity vulnerability.
The makeAddr
helper function is used to setup an attacker
address to call the setPasword()
function:
The following test, sets the password to "attackerPassword"
using the attacker address. When run, this test will pass, demonstrating that the attacker can set the password:
Run the test:
Which yields the following output:
Include access control to restrict who can call the setPassword
function to be only the owner: s_owner
. This can be achieved in two ways:
Using an if
statement, as used in the getPassword
function, and revert with the PasswordStore__NotOwer()
custom error if the address calling the function is not the owner:
Using an access modifier e.g. OpenZeppelin's onlyOwner
. To use this modifier, the PasswordStore
contract will need to inherit from OpenZeppelin's Ownable
contract and call it's constructor inside the constructor of PasswordStore
:
As per the OpenZeppelin documentation, by default, the owner
of an Ownable
contract is the account that deployed it, meaning that the s_owner
state variable can be removed.
Using onlyOwner
modifier adds logic to check that the msg.sender
is the owner
of the contract before executing the function's logic:
Anyone can call `setPassword` and set a new password contrary to the intended purpose.
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.