3

My tests seem to indicate that it is trivailly easy to spoof an "only owner" modifier on a view or pure.

For example, this contract:

pragma solidity 0.8.6;

contract Test {
    address private owner;
    string private secret;

    modifier onlyOwner() {
        require(msg.sender==owner,"onlyOwner");
        _;
    }

    constructor() {
        owner = msg.sender;
        secret="Abracadabra";
    }

    function setSecret(string memory newSecret) public onlyOwner {
        secret = newSecret;
    }
    function getSecret() public view **onlyOwner** returns(string memory) {
        return secret;
    }
    
}

So if the design intention was that you could only get or set a secret (and I understand that "there are no secrets on the blockchain") if called by the "owner" address et int he contsructor, it doesn't appear that you can actually enforce that, because using ether.contract.connect(). can call a view function with a string of the account address instead of with a signer.

So if, in hardhat you execute something like this:

   [signer0, signer1]= await ethers.getSigners();
    let testFactory = await ethers.getContractFactory("Test");
    let test = await testFactory.connect(signer1).deploy();
    let signer1Address = signer1.address;  //get string version of address
    --> let secret1 = await test.connect(signer1Address).getSecret();
    console.log(secret1); //"Abracadabra"

You get the expected secret even if all you have available is the account owner address, even you don't have the account in your wallet and dont have the keys.

So if that is the case, is there any way to really enforce any kind of require msg.sender== condition reliably in a view or pure function?

1
  • you're right. after re-reading your question I admit I missed the crucial point that you were talking only about view/pure methods meaning no sig required, and you're right that it's trivially easy to spoof being the owner in that scenario. I've deleted my answer original answer 'cause it missed the point
    – sola24
    Jul 9, 2022 at 9:09

1 Answer 1

1

After some testing and examining ethers.js code, the answer is no, there's no way to fully trust msg.sender in a view or pure function. Signatures are not verified in simple calls, so you can provide whatever address you want in the call, which is the address that will be reported in msg.sender. One way to fully assure yourself of who is calling a function, is to have the caller sign and message and then check the message signature inside the function. Although if the purpose is to 'hide' the value of a some state variable that won't work without some form of encryption since everything recorded on the blockchain is discoverable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.