Vesting Account Preemption Attack Preventing Future Contract Deployment #60
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
edited-by-warden
H-01
primary issue
Highest quality submission among a set of duplicates
satisfactory
satisfies C4 submission criteria; eligible for awards
selected for report
This submission will be included/highlighted in the audit report
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/NibiruChain/nibiru/blob/f3cbcaec58f23c54f6b75204b0c4009856b47250/x/evm/keeper/statedb.go#L130-L134
Vulnerability details
Finding description and impact
This vulnerability allows an attacker to preemptively set a target address as a vesting account, permanently blocking contract deployments by Factory contracts or other users to that address. Once the address is marked as a vesting account, any deployment attempt stores the contract bytecode in the state without creating a codeHash, rendering the contract permanently inaccessible.
For example, an attacker could target critical ecosystem addresses, such as those planned for LayerZero or Uniswap, and preemptively mark them as vesting accounts. This would effectively “orphan” the contract bytecode at these addresses, with no way to interact with or access it. The severity is compounded if funds are deployed with the contract, as these would also be irretrievable.
If exploited, this vulnerability allows an attacker to lock up critical addresses by setting them as vesting accounts, resulting in “lost” contracts with unreachable bytecode and permanently inaccessible funds. For ecosystem-critical contracts or high-value deployments, this could disrupt functionality and lead to substantial, irreversible losses.
Proof of Concept
The following commit demonstrates the vulnerability through a step-by-step exploit:
TestVestingAccountPreemptionAttack
, which provides a proof of concept for the vulnerability in the form of a test scenario.Please provide your GitHub handles, and I will grant access to the private repository.
For quick reference before access permissions are granted, I’ve included a core snippet of the reproduction code below.
Test Code Walkthrough:
x/evm/embeds/contracts/Factory.sol
.PermanentLockedAccount
at the anticipated child contract address (lines 313–319). This immediately disrupts the normal functionality of the first future child deployed by the factory. If the attacker creates vesting accounts across multiple nonces within a for loop, this would effectively block any future child contract deployments by the factory. The following steps demonstrate the resulting impacts.makeChild
on the factory contract (lines 322–339). The transaction to deploy the child succeeds, but something has gone wrong.SetAccount
, where the codeHash is only set if the account implementsEthAccountI
. Because the account here is a PermanentLockedAccount, the codeHash is not set. With no mapping between the contract address and the codeHash, the deployed bytecode is permanently inaccessible.Manual Reproduce
46e86cbf25a9aeb0630feebbb4ec22d6ee7acbdbde8b54d0382112c9b0cfe37c
.nibid tx vesting create-permanent-locked-account nibi136uvp9vz8qplx4rc32fpju5natuacvvgau96c6 10unibi --from attacker
Child.withdraw
from victim account. No state transition will occur, and no funds will be retrievable due to the missing codeHash.Recommended mitigation steps
There are two potential approaches for patching this vulnerability: a fundamental patch and a more practical one.
The fundamental approach involves completely separating the Cosmos address system from the EVM address system. Currently, the bytes of an EVM address are directly used as Cosmos addresses, allowing them to share state, which enables this vulnerability. By fully decoupling these address systems, this issue could be prevented entirely. However, this would require a major design overhaul and is thus not a realistic solution.
The more practical approach is to disable the Vesting Account feature at the ante handler level. While this would prevent the use of vesting features, it is likely a necessary trade-off for security reasons.
The text was updated successfully, but these errors were encountered: