VYPR
High severityNVD Advisory· Published Aug 5, 2022· Updated Apr 22, 2025

Ethermint DoS through Unintended Contract Selfdestruct

CVE-2022-35936

Description

Ethermint is an Ethereum library. In Ethermint running versions before v0.17.2, the contract selfdestruct invocation permanently removes the corresponding bytecode from the internal database storage. However, due to a bug in the DeleteAccountfunction, all contracts that used the identical bytecode (i.e shared the same CodeHash) will also stop working once one contract invokes selfdestruct, even though the other contracts did not invoke the selfdestruct OPCODE. This vulnerability has been patched in Ethermint version v0.18.0. The patch has state machine-breaking changes for applications using Ethermint, so a coordinated upgrade procedure is required. A workaround is available. If a contract is subject to DoS due to this issue, the user can redeploy the same contract, i.e. with identical bytecode, so that the original contract's code is recovered. The new contract deployment restores the bytecode hash -> bytecode entry in the internal state.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

In Ethermint before v0.17.2, a bug in DeleteAccount causes a denial of service by permanently removing bytecode shared by all contracts with the same CodeHash when one contract selfdestructs.

Vulnerability

Overview

CVE-2022-35936 is a denial-of-service (DoS) vulnerability in Ethermint, an Ethereum library, affecting versions prior to v0.17.2. The root cause lies in the DeleteAccount function, which incorrectly removes the entire bytecode entry associated with a given CodeHash from the internal database when any contract invokes the selfdestruct opcode. Because bytecode is stored as a key-value pair (bytecode hash → bytecode) shared among all contracts that use identical bytecode, the deletion impacts every contract with that hash, not just the one that self-destructed [1][2].

Exploitation and

Attack Surface

An attacker can exploit this by first identifying a vulnerable contract that supports selfdestruct. They then deploy a copy of that contract with the same bytecode and trigger selfdestruct on their copy. This action deletes the shared bytecode entry, causing all other contracts with the same CodeHash to become non-functional. Every transaction interacting with those contracts will fail until a workaround is applied [2]. No special network access or authentication beyond what is needed to deploy and call a contract is required.

Impact

The primary impact is a persistent denial of service for all smart contracts that share bytecode with the contract that was self-destructed. The vulnerability does not affect contract state, storage values, or user funds; only the ability to execute code is lost. This can disrupt dependent applications and end-users who rely on the affected contracts [1][2].

Mitigation

Status

The vulnerability has been patched in Ethermint version v0.18.0. However, the patch introduces state machine-breaking changes, so a coordinated upgrade procedure is necessary for applications using Ethermint. As a workaround, users can redeploy a contract with identical bytecode to restore the code entry in the internal state [1][3]. The commit implementing the fix removes the problematic code deletion logic from the DeleteAccount function [3][4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/evmos/ethermintGo
< 0.18.00.18.0
github.com/evmos/evmosGo
< 7.0.07.0.0
github.com/crypto-org-chain/cronosGo
< 0.7.1-rc20.7.1-rc2
github.com/Kava-Labs/kavaGo
< 0.18.00.18.0

Affected products

6

Patches

1
144741832007

Merge pull request from GHSA-f92v-grc2-w2fg

https://github.com/evmos/ethermintFreddy CaceresAug 4, 2022via ghsa
2 files changed · +20 8
  • x/evm/keeper/statedb.go+1 8 modified
    @@ -1,7 +1,6 @@
     package keeper
     
     import (
    -	"bytes"
     	"fmt"
     	"math/big"
     
    @@ -186,7 +185,7 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
     	}
     
     	// NOTE: only Ethereum accounts (contracts) can be selfdestructed
    -	ethAcct, ok := acct.(ethermint.EthAccountI)
    +	_, ok := acct.(ethermint.EthAccountI)
     	if !ok {
     		return sdkerrors.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr)
     	}
    @@ -196,12 +195,6 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error {
     		return err
     	}
     
    -	// remove code
    -	codeHashBz := ethAcct.GetCodeHash().Bytes()
    -	if !bytes.Equal(codeHashBz, types.EmptyCodeHash) {
    -		k.SetCode(ctx, codeHashBz, nil)
    -	}
    -
     	// clear storage
     	k.ForEachStorage(ctx, addr, func(key, _ common.Hash) bool {
     		k.SetState(ctx, addr, key, nil)
    
  • x/evm/keeper/statedb_test.go+19 0 modified
    @@ -15,6 +15,7 @@ import (
     	ethtypes "github.com/ethereum/go-ethereum/core/types"
     	"github.com/ethereum/go-ethereum/core/vm"
     	"github.com/ethereum/go-ethereum/crypto"
    +	"github.com/evmos/ethermint/crypto/ethsecp256k1"
     	"github.com/evmos/ethermint/tests"
     	"github.com/evmos/ethermint/x/evm/statedb"
     	"github.com/evmos/ethermint/x/evm/types"
    @@ -420,12 +421,26 @@ func (suite *KeeperTestSuite) TestSuicide() {
     	suite.Require().NoError(db.Commit())
     	db = suite.StateDB()
     
    +	// Generate 2nd address
    +	privkey, _ := ethsecp256k1.GenerateKey()
    +	key, err := privkey.ToECDSA()
    +	suite.Require().NoError(err)
    +	addr2 := crypto.PubkeyToAddress(key.PublicKey)
    +
    +	// Add code and state to account 2
    +	db.SetCode(addr2, code)
    +	suite.Require().Equal(code, db.GetCode(addr2))
    +	for i := 0; i < 5; i++ {
    +		db.SetState(addr2, common.BytesToHash([]byte(fmt.Sprintf("key%d", i))), common.BytesToHash([]byte(fmt.Sprintf("value%d", i))))
    +	}
    +
     	// Call Suicide
     	suite.Require().Equal(true, db.Suicide(suite.address))
     
     	// Check suicided is marked
     	suite.Require().Equal(true, db.HasSuicided(suite.address))
     
    +	// Commit state
     	suite.Require().NoError(db.Commit())
     	db = suite.StateDB()
     
    @@ -441,6 +456,10 @@ func (suite *KeeperTestSuite) TestSuicide() {
     
     	// Check account is deleted
     	suite.Require().Equal(common.Hash{}, db.GetCodeHash(suite.address))
    +
    +	// Check code is still present in addr2 and suicided is false
    +	suite.Require().NotNil(db.GetCode(addr2))
    +	suite.Require().Equal(false, db.HasSuicided(addr2))
     }
     
     func (suite *KeeperTestSuite) TestExist() {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.