Submitted by RadiantLabs, also found by oakcobalt
The DualVmToken is a utility EVM contract allowing Kakarot EVM accounts to operate Starknet ERC-20s via classic balanceOf(), transfer() etc. operations.
Calls to the DualVmToken contract are routed via CairoLib -> kakarot_precompiles.cairo -> account_contract.cairo, which finally makes a call to the call_contract() Cairo 0 syscall to invoke the appropriate Starknet ERC-20 contract.
If we look at how the execute_starknet_call() function in account_countract.cairo is implemented:
We see that the function admits graceful failures (by returning a success: felt value that can be FALSE), which are then properly handled in the calling precompile. However, the actual call to the target contract (at L347) does not return a success boolean, and instead uses the call_contract syscall which panics on failures.
This means that any call that panics in the called contract can cause a revert at RPC level.
To illustrate how this is not a hypothetical scenario, but a very likely one that can be achieved also with the DualVmToken contract that is in scope and consequently planned to be whitelisted to make this call, we make a simple example:
In this scenario, standard OpenZeppelin ERC-20 implementations panic, bubbling up the error up to the Kakarot RPC level.
This also means that most of the ERC-20 behaviours Kakarot intends to support will lead to reverts at the RPC level if encountered.  The following table shows the effect of each behaviour if encountered in a call to a DualVmToken:
Any contract can use the above over-transfer call to cause RPC-level crashes in the Kakarot EVM, regardless of how defensively they were called. Protective measures generally considered safe in the EVM space like ExcessivelySafeCall (which is used in LayerZero cross-chain applications to prevent channel DoSes that can permanently freeze in-flight tokens), can be bypassed by causing a RPC-level cairo revert.
More generally, any transaction containing a call to a reverting DualVmToken at any depth will revert. This means contracts whose logic requires such a call to succeed will be temporarily (if the call eventually succeeds) or permanently bricked.
The RPC-level panic can be proved by simply editing the test_should_transfer in test_dual_vm_token.py end-to-end test to transfer balance_owner_before + amount instead of amount at L110.
The new AccountContract Cairo 1 implementation uses the Cairo 1 call_contract syscall, which offers a recoverable error interface through a nopanic signature returning a Result. If it is not possible to deploy the new version, the Cairo 1 syscall can be used from the Cairo 0 account_contract via a library call as is done with other functionality.
ClementWalter (Kakarot) confirmed and commented:
LSDan (judge) decreased severity to Medium and commented:
obatirou (Kakarot) commented:
Kakarot mitigated:
Status: Mitigation confirmed.
