Open zobront opened 9 months ago
Do you have ideas about how this could be addressed?
I'm leaning towards considering this a non-issue on the basis that there is inherently some trust placed on the callback target. This also sounds very similar to ERC20's approve frontrunning risk, which nowadays seems to be considered a non-issue as well.
Yeah, after more thought, I think I'm with you. Like you said (and everyone agreed with ERC20 approve frontrunning), if someone malicious has an approval already, this doesn't really increase the risk surface area.
I might add a section to the Security Considerations section of the EIP mentioning it in case it happens to matter for a specific project, but agree that any fix in the code would be overkill.
I'm not sure if this is a problem, but I'm auditing a protocol using ERC6909X and it crossed my mind as something that could cause an issue in certain specific circumstances, so figured I'd share...
As you mention in the EIP, the signatures allowing for approvals are publicly visible in the mempool. It is assumed that this visibility is safe because anyone using the signature should be forced to execute the exact callback specific in the signed data, and therefore will get the same results as were intended by the signer (with other protections you mention in the
Security Considerations
section).However, there is one specific situation where this assumption may not hold: if an attacker nests an approval signature within a temporary approval call, its action will be undone when the temporary approval is unwound. This will use the nonce and burn the signature without getting the intended result.
Example
Let's imagine a situation where a user has approved a spender to spent 10e18 of their token. They need the send 11e18 of the token, and afterwards, they want to reset the approval to zero. How do they do it?
The most commonsense option using ERC6909X would be to issue two transactions:
1)
temporaryApproveAndCallBySig()
with an_amount
of11e18
(nonce X) 2)approveBySig()
with an_amount
of0
(nonce X + 1)Both transactions are sent to the mempool, with both signatures visible. When the
temporaryApproveAndCallBySig()
transaction is started, theprevAllowance
of10e18
is cached. We then make theonTemporaryApprove()
call.Within this call, the attacker regains control flow, and can use it (along with the signature from the mempool) to call
approveBySig()
. This will pass (nonce = X + 1) and set the approved amount to0
.But after the call ends, the outer temporary function will reset the allowance to 10e18.
Both signatures will be "used up" (because their nonces will be used), but the result is that the spender will retain their approval.
In the event that signatures are difficult to obtain (or can't be obtained again), or that the spender has unlimited access to temporary transaction signatures (say, from a server that's been permissioned to give them in certain circumstances), this could block the user's ability to revoke access from the spender.