Crypto Twitter(I refuse to call it X) has not read the memo that it is the holidays and that it is time to go touch some (possibly snow covered) grass. There has been discussion about supply chain hacks of the software supporting hardware wallets, smart contract bugs, and reverse hacks as well. There is also a growing drumbeat of “EIP-3074 fixes this.”
Properly used EIP-3074 can fix some of our recent hacks. It can be used to provide specific instructions to a specific invoker to execute at a future date, such as transferring an asset to a different address once a fee has been paid. And store that authorization off-chain, until the sale is closed. This structure has the added advantage of being private, which ERC-20 and ERC-721 approvals lack. But EIP-3074 is not without risk, there are new classes of problems it opens up that the current spec currently does not mitigate properly.
What is EIP-3074? It is an EIP that allows wallets to sign a message that operates like something between setuid and sudo for externally owned accounts. You can sign a message and contracts can present that message to the EVM and it will allow a specific contract to take actions as though they are the EOA signing the message. Messages are only valid for a specific invoker on a specific chain. It is a significant departure from the security model that meta-transactions and Account Abstraction proposals like ERC-4337 have because it requires a protocol change.
The problem I have with EIP-3074 isn’t the utility. That is undeniable. The concerns I have are with the security profile. An Ethereum Magicians thread from 2021 does a good job outlining the top 4 issues at that time: (1) it violates the Principle of Least Privilege, (2) Buggy or Malicious Invokers will exist, (3) Authorizations are Eternal, and (4) Clever attacks could be made to use authorizations cross-chain.
To address issue #4 the EIP was adjusted to include the chain ID in the AUTH message. EVMs are not supposed to accept authorization when there is a chain-id mismatch. This is a great solution to that issue but does nothing to address issues #3 and #2. EIP-3074 messages are like gossip: once signed they cannot be unsigned. Once shared they cannot be unshared.
There are two issues with this permanence. First, foundations tend to shift over time. Security attacks only get better, they don’t get worse. What was once seen as a safe contract can suddenly become vulnerable to exploit. Your authorization that once had perfect opsec and checked all the audit boxes could become vulnerable to a previously unknown EVM exploit. There could be an undetected bug in the compiler used to compile the Invoker. The company holding the upgrade keys to the proxy contracts you authorized may have sold operations to a new group you don’t fully trust. In this landscape an eternal authorization takes on a level of risk all users may not be comfortable with.
Second, is that mistaken authorizations will occur. Not every user is attentive to what they sign. Some users have been targets of very clever and sophisticated phishing attacks. And a new twist has recently occurred proving that it can happen: supply chain attacks against wallet software.
These two issues are not new, they exist in smart contracts today. People do questionable things, and bad things happen to otherwise prepared people. Headlines get made and we all slap our foreheads. But while not all the impacts can (or should) be undone at least there is a way to stop future problems. ERC-20 and ERC-721 approvals can be revoked. Permits can be unpermitted. Tools like revoke.cash can make that super easy for you. But EIP-3074, as currently written, does not have any way to undo an authorization message. The damage caused by existing behavior patterns will grow significantly if this EIP is adopted in its current form.
There is a way to have our cake and eat it too. A way to get the value from an EVM setuid operation and not force every EOA to accept a risk profile of permanent delegation. Make AUTH messages revocable. Thus authorizations will never be eternal and buggy or malicious invokers will only have a closable window to exploited.
The mechanism I propose is to get rid of the AUTH opcode from the spec and replace it with a System Contract that sets the same context variable. The AUTHCALL opcode would remain the same.
This isn’t as crazy as I once thought, digging through the change history of EIP-3074 you can see that the first proposal was for a pair of precompiles. Because there were no “stateful precompiles” at the time this design was changed to a pair of opcodes. But Cancun is set to add the EIP-4788 system contract, which is a stateful precompile. However having a system contract that results in deeper calls from the system address is a new feature, and one that will look weird in opcode traces and will immediately break some dev tooling. So having an opcode that acts like a new form of a CALL, that depends on a system contract setting a context variables, is probably the most useful configuration.
The calling conventions for the AUTH contract would be Solidity ABI (first four bytes are the selector) and would include at least two functions, one to set the authorization (like the AUTH opcode), and another to revoke authorizations. The revoke function would need to track the revocations in storage, likely an array indexed by the hash of the address extracted from the signature and the commit it is signing. Hashing the address instead of the signature prevents re-signing the same commit as ECDSA sigs are not deterministic. Invokers that want to allow re-authorizations should have a nonce or some other variable data scheme if they want to re-authorize the same functional commit. Authorizations leave no state shadow, only revocations create new state.
One other aspect of the proposal I didn’t like, but wasn’t bad enough to cause problems, was the one-size-fits-all authorization scheme. With system contract based authorizations rollups and alternate chains have space to innovate in a compatible fashion with other chains. Is eternal authorizations desirable for one chain? They can provide an implementation of the precompile that breaks revocations.
Customizations can be provided via new function selectors. Perhaps a rollup only wants time-limited authorizations, they can provide a new function that accepts AUTH messages with that time limits or nonce limits. Maybe a rollup wants to address the principle of least privilege and have some authorizations that only allow identity and not value transfer, a new function can be written for that.
Rollups can innovate in non-authorization ways as well. A system contract could provide a view function that could tell a contract if the parent call was an AUTHCALL or if any parent call was an AUTHCALL, in case the contract does not want to accept delegation or if it wants to require delegation. Information about the commitment could also be shared and a contract could maintain its own rejection list.
Other options are for rollups to provide multiple precompiles that can set the authorized context variable. Perhaps a rollup has a dramatically different security model, they can provide authorizations at a different address. Maybe there are reasons to break lift-and-shift porting of smart contracts from other chains, the standard AUTH contract can be moved to a new address *cries in regulatory tears*.
One important aspect to note about this solution is that it still preserves the invokers flexibility to innovate. Invokers can have rich meaning to their commitment that is not implied or directed by the terms of the EIP. Any security model the invokers apply is in addition to any security considerations applied by the chain or the rollup. In effect it is the union of the security constraints. If a rollup adds authorization introspection it can be the union of all three aspects, the EOA, the Invoker, and the execution contract, that can reject or cancel a transaction it doesn’t like.
With iteration over the security implications, such as adding a revocation mechanism, we can have our cake and eat it too. For EIP-3074 to truly be the setuid of ethereum we need to have a way to un-set the sticky bit.
Crypto Twitter(I refuse to call it X) has not read the memo that it is the holidays and that it is time to go touch some (possibly snow covered) grass. There has been discussion about supply chain hacks of the software supporting hardware wallets, smart contract bugs, and reverse hacks as well. There is also a growing drumbeat of “EIP-3074 fixes this.”
Properly used EIP-3074 can fix some of our recent hacks. It can be used to provide specific instructions to a specific invoker to execute at a future date, such as transferring an asset to a different address once a fee has been paid. And store that authorization off-chain, until the sale is closed. This structure has the added advantage of being private, which ERC-20 and ERC-721 approvals lack. But EIP-3074 is not without risk, there are new classes of problems it opens up that the current spec currently does not mitigate properly.
What is EIP-3074? It is an EIP that allows wallets to sign a message that operates like something between setuid and sudo for externally owned accounts. You can sign a message and contracts can present that message to the EVM and it will allow a specific contract to take actions as though they are the EOA signing the message. Messages are only valid for a specific invoker on a specific chain. It is a significant departure from the security model that meta-transactions and Account Abstraction proposals like ERC-4337 have because it requires a protocol change.
The problem I have with EIP-3074 isn’t the utility. That is undeniable. The concerns I have are with the security profile. An Ethereum Magicians thread from 2021 does a good job outlining the top 4 issues at that time: (1) it violates the Principle of Least Privilege, (2) Buggy or Malicious Invokers will exist, (3) Authorizations are Eternal, and (4) Clever attacks could be made to use authorizations cross-chain.
To address issue #4 the EIP was adjusted to include the chain ID in the AUTH message. EVMs are not supposed to accept authorization when there is a chain-id mismatch. This is a great solution to that issue but does nothing to address issues #3 and #2. EIP-3074 messages are like gossip: once signed they cannot be unsigned. Once shared they cannot be unshared.
There are two issues with this permanence. First, foundations tend to shift over time. Security attacks only get better, they don’t get worse. What was once seen as a safe contract can suddenly become vulnerable to exploit. Your authorization that once had perfect opsec and checked all the audit boxes could become vulnerable to a previously unknown EVM exploit. There could be an undetected bug in the compiler used to compile the Invoker. The company holding the upgrade keys to the proxy contracts you authorized may have sold operations to a new group you don’t fully trust. In this landscape an eternal authorization takes on a level of risk all users may not be comfortable with.
Second, is that mistaken authorizations will occur. Not every user is attentive to what they sign. Some users have been targets of very clever and sophisticated phishing attacks. And a new twist has recently occurred proving that it can happen: supply chain attacks against wallet software.
These two issues are not new, they exist in smart contracts today. People do questionable things, and bad things happen to otherwise prepared people. Headlines get made and we all slap our foreheads. But while not all the impacts can (or should) be undone at least there is a way to stop future problems. ERC-20 and ERC-721 approvals can be revoked. Permits can be unpermitted. Tools like revoke.cash can make that super easy for you. But EIP-3074, as currently written, does not have any way to undo an authorization message. The damage caused by existing behavior patterns will grow significantly if this EIP is adopted in its current form.
There is a way to have our cake and eat it too. A way to get the value from an EVM setuid operation and not force every EOA to accept a risk profile of permanent delegation. Make AUTH messages revocable. Thus authorizations will never be eternal and buggy or malicious invokers will only have a closable window to exploited.
The mechanism I propose is to get rid of the AUTH opcode from the spec and replace it with a System Contract that sets the same context variable. The AUTHCALL opcode would remain the same.
This isn’t as crazy as I once thought, digging through the change history of EIP-3074 you can see that the first proposal was for a pair of precompiles. Because there were no “stateful precompiles” at the time this design was changed to a pair of opcodes. But Cancun is set to add the EIP-4788 system contract, which is a stateful precompile. However having a system contract that results in deeper calls from the system address is a new feature, and one that will look weird in opcode traces and will immediately break some dev tooling. So having an opcode that acts like a new form of a CALL, that depends on a system contract setting a context variables, is probably the most useful configuration.
The calling conventions for the AUTH contract would be Solidity ABI (first four bytes are the selector) and would include at least two functions, one to set the authorization (like the AUTH opcode), and another to revoke authorizations. The revoke function would need to track the revocations in storage, likely an array indexed by the hash of the address extracted from the signature and the commit it is signing. Hashing the address instead of the signature prevents re-signing the same commit as ECDSA sigs are not deterministic. Invokers that want to allow re-authorizations should have a nonce or some other variable data scheme if they want to re-authorize the same functional commit. Authorizations leave no state shadow, only revocations create new state.
One other aspect of the proposal I didn’t like, but wasn’t bad enough to cause problems, was the one-size-fits-all authorization scheme. With system contract based authorizations rollups and alternate chains have space to innovate in a compatible fashion with other chains. Is eternal authorizations desirable for one chain? They can provide an implementation of the precompile that breaks revocations.
Customizations can be provided via new function selectors. Perhaps a rollup only wants time-limited authorizations, they can provide a new function that accepts AUTH messages with that time limits or nonce limits. Maybe a rollup wants to address the principle of least privilege and have some authorizations that only allow identity and not value transfer, a new function can be written for that.
Rollups can innovate in non-authorization ways as well. A system contract could provide a view function that could tell a contract if the parent call was an AUTHCALL or if any parent call was an AUTHCALL, in case the contract does not want to accept delegation or if it wants to require delegation. Information about the commitment could also be shared and a contract could maintain its own rejection list.
Other options are for rollups to provide multiple precompiles that can set the authorized context variable. Perhaps a rollup has a dramatically different security model, they can provide authorizations at a different address. Maybe there are reasons to break lift-and-shift porting of smart contracts from other chains, the standard AUTH contract can be moved to a new address *cries in regulatory tears*.
One important aspect to note about this solution is that it still preserves the invokers flexibility to innovate. Invokers can have rich meaning to their commitment that is not implied or directed by the terms of the EIP. Any security model the invokers apply is in addition to any security considerations applied by the chain or the rollup. In effect it is the union of the security constraints. If a rollup adds authorization introspection it can be the union of all three aspects, the EOA, the Invoker, and the execution contract, that can reject or cancel a transaction it doesn’t like.
With iteration over the security implications, such as adding a revocation mechanism, we can have our cake and eat it too. For EIP-3074 to truly be the setuid of ethereum we need to have a way to un-set the sticky bit.
...and they shall know me by my speling errors. Opinions are my own. Ethereum Core Developer and Fanboy. x-Oracle, x-Google, x-ConsenSys
...and they shall know me by my speling errors. Opinions are my own. Ethereum Core Developer and Fanboy. x-Oracle, x-Google, x-ConsenSys
Share Dialog
Share Dialog

Subscribe to Danno Ferrin

Subscribe to Danno Ferrin
<100 subscribers
<100 subscribers
No activity yet