Ethermint DoS through Unintended Contract Selfdestruct
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.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/evmos/ethermintGo | < 0.18.0 | 0.18.0 |
github.com/evmos/evmosGo | < 7.0.0 | 7.0.0 |
github.com/crypto-org-chain/cronosGo | < 0.7.1-rc2 | 0.7.1-rc2 |
github.com/Kava-Labs/kavaGo | < 0.18.0 | 0.18.0 |
Affected products
6- ghsa-coords4 versionspkg:golang/github.com/crypto-org-chain/cronospkg:golang/github.com/evmos/ethermintpkg:golang/github.com/evmos/evmospkg:golang/github.com/kava-labs/kava
< 0.7.1-rc2+ 3 more
- (no CPE)range: < 0.7.1-rc2
- (no CPE)range: < 0.18.0
- (no CPE)range: < 7.0.0
- (no CPE)range: < 0.18.0
- evmos/ethermintv5Range: <= 0.17.2
Patches
1144741832007Merge pull request from GHSA-f92v-grc2-w2fg
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- github.com/advisories/GHSA-f92v-grc2-w2fgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-35936ghsaADVISORY
- github.com/evmos/ethermint/blob/c9d42d667b753147977a725e98ed116c933c76cb/x/evm/keeper/statedb.goghsax_refsource_MISCWEB
- github.com/evmos/ethermint/commit/144741832007a26dbe950512acbda4ed95b2a451ghsax_refsource_MISCWEB
- github.com/evmos/ethermint/security/advisories/GHSA-f92v-grc2-w2fgghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.