Generated banner for Cosmos Vulnerability Scanner
Generated logo for Cosmos Vulnerability Scanner

Cosmos Vulnerability Scanner

Trail of BitsOfficialPublished by Trail of Bits

  • Skill
  • Workflow
  • Security
  • CC-BY-SA-4.0
  • No issues found

From the author

Scans Cosmos SDK blockchain modules and CosmWasm contracts for consensus-critical vulnerabilities — chain halts, fund loss, state divergence. 25 core + 16 IBC + 10 EVM + 3 CosmWasm patterns. Use when auditing custom x/ modules, reviewing IBC integrations, or assessing pre-launch chain security. Updated for SDK v0.53.x.
— the description by Trail of Bits

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The Cosmos Vulnerability Scanner is an automated security auditing tool designed for Cosmos SDK-based blockchains. It performs a multi-phase analysis of custom modules and smart contracts to identify vulnerabilities that could lead to chain halts, state divergence, or loss of funds. The skill orchestrates parallel scanning agents that evaluate code against specific patterns related to core SDK logic, IBC integrations, EVM compatibility, and CosmWasm contracts. It emphasizes consensus-critical execution paths, ensuring that findings are relevant to the blockchain's stability and security.

What it does

  • Generates a technical inventory and threat model via a discovery phase.
  • Spawns parallel scanning agents to analyze code against predefined vulnerability patterns.
  • Filters findings to focus exclusively on consensus-critical execution paths.
  • Supports specialized scanning for IBC, EVM, and CosmWasm components.
  • Writes detailed vulnerability reports as individual markdown files.
  • Verifies that all required security patterns have been assessed.

When to use it

  • Auditing custom Cosmos SDK modules.
  • Reviewing CosmWasm smart contracts for security flaws.
  • Conducting pre-launch security assessments for Cosmos-based chains.
  • Investigating potential causes of chain halt incidents.

Advantages

  • Reduces manual audit time through parallelized scanning.
  • Focuses on high-impact consensus-critical bugs.
  • Provides structured, actionable findings for remediation.
  • Adapts to specific Cosmos SDK version requirements.

Usage examples

“Run a security scan on the current directory.”
The agent performs a discovery phase, identifies the platform and SDK version, executes parallel scans, and generates a report in the .bughunt_cosmos/ directory.
“Audit my custom x/ modules and save findings to /tmp/audit_results.”
The agent scans the codebase for consensus-critical vulnerabilities and outputs individual markdown files containing findings to the specified directory.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/trailofbits/cosmos-vulnerability-scanner/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip cosmos-vulnerability-scanner.zip -d .agents/skills

Documentation by Trail of Bits

Cosmos Vulnerability Scanner

Purpose

Scan Cosmos SDK modules and CosmWasm contracts for vulnerabilities that cause chain halts, consensus failures, or fund loss. Spawns parallel scanning agents — each specializing in a vulnerability category — that return findings to the main skill, which then writes them as individual markdown files to an output directory.

Output directory: defaults to .bughunt_cosmos/. If the user specifies a different directory in their prompt, use that instead.

When to Use

  • Auditing Cosmos SDK modules (custom x/ modules)

  • Reviewing CosmWasm smart contracts

  • Pre-launch security assessment of Cosmos chains

  • Investigating chain halt incidents

When NOT to Use

  • Pure Solidity/EVM audits without Cosmos SDK — use Solidity-specific tools

  • CometBFT consensus engine internals — this covers SDK modules, not the consensus layer itself

  • General Go code review with no blockchain context

  • Cosmos SDK application logic that is not consensus-critical (e.g., CLI commands, REST endpoints)

  • CosmWasm contract-only audits on chains without custom SDK modules — use the CosmWasm checklist items alone

Essential Principles

  1. Consensus path is king — A bug only matters for chain halt/fund loss if it's on the consensus-critical execution path (BeginBlock, EndBlock, FinalizeBlock, msg_server handlers, AnteHandler). Always verify a finding is reachable from consensus before reporting it.

  2. State divergence = chain halt — Any non-determinism that causes validators to compute different state roots will halt the chain. This is the highest-severity class because it affects all validators simultaneously.

  3. Check the version — Cosmos SDK has breaking changes across major versions (v0.47 removed GetSigners, v0.50 added ABCI 2.0, v0.53 deprecated ValidateBasic). Always check go.mod versions before applying patterns.

  4. False positives waste audit time — A map iteration in a CLI command is not a consensus bug. A panic in a query handler does not halt the chain. Verify the execution context before flagging.

  5. Cross-module interactions are where bugs hide — The most severe findings (IBC reentrancy, EVM/Cosmos state desync, authz escalation) involve interactions between modules, not bugs within a single module.

Scanning Workflow

Phase 1: Discovery (synchronous)

Entry: Target codebase path provided by user. Codebase contains Go source (e.g., x/ modules, go.mod) or Rust contracts with cosmwasm_std.

Run a synchronous subagent (Agent tool) with the full contents of DISCOVERY.md as its prompt. The agent must:

  1. Follow the Discovery workflow to explore the target codebase

  2. Return the full CLAUDE.md content (the technical inventory and threat model) in its response

  3. Return a structured summary with exactly these fields:

PLATFORM: pure-cosmos | evm | wasm        (pick one; if multiple, comma-separated)
IBC_ENABLED: true | false
SDK_VERSION: <version from go.mod>
IBC_GO_VERSION: <version from go.mod, or "n/a">
CUSTOM_MODULES: <comma-separated list of x/* modules>

After the subagent returns, you (the main skill) Write the CLAUDE.md to the target repo root. Save its path and the discovery values — these feed into Phase 2.

Exit: CLAUDE.md written by main skill. PLATFORM, IBC_ENABLED, SDK_VERSION, IBC_GO_VERSION, and CUSTOM_MODULES captured.

Phase 2: Parallel Vulnerability Scan

Spawn scanning agents in a single message for maximum parallelism. Use the Agent Prompt Template below, filling in the reference file for each agent. Subagents only need read access (Grep, Glob, Read) — they return findings in their response and the main skill writes the files.

Always spawn these 3 agents:

Agent NameReference FileScope
core-scannerVULNERABILITY_PATTERNS.md§1-9: non-determinism, ABCI, signers, validation, handlers, ante security
state-scannerSTATE_VULNERABILITY_PATTERNS.md§11-23: bookkeeping, bank, pagination, events, tx replay, governance, arithmetic, encoding, deprecated modules
advanced-scannerADVANCED_VULNERABILITY_PATTERNS.md§24-27: storage keys, consensus validation, circuit breaker, crypto

Spawn conditionally (in the same parallel message):

Agent NameConditionReference File
evm-scannerPLATFORM includes evmEVM_VULNERABILITY_PATTERNS.md
ibc-scannerIBC_ENABLED is trueIBC_VULNERABILITY_PATTERNS.md
cosmwasm-scannerPLATFORM includes wasmCOSMWASM_VULNERABILITY_PATTERNS.md
Agent Prompt Template

Construct each agent's prompt by replacing {REFERENCE_FILE_PATH} with the full path to the reference file (under {baseDir}/resources/) and {CLAUDE_MD_PATH} with the path to the CLAUDE.md written in Phase 1:

Perform a very thorough security scan of a Cosmos SDK codebase for specific vulnerability patterns.

CONTEXT:
Read {CLAUDE_MD_PATH} for codebase context (SDK version, modules, threat model, key files).

PATTERNS:
Read {REFERENCE_FILE_PATH} — it contains numbered vulnerability patterns. For EACH pattern:
1. Read the detection patterns and "What to Check" items
2. Use Grep and Glob to search the target codebase for each pattern
3. When a match is found, Read surrounding code to verify it's on a consensus-critical path (BeginBlock, EndBlock, FinalizeBlock, msg_server handlers, AnteHandler)
4. Classify severity per the guidelines below

RULES:
- Consensus path only: Only flag code reachable from consensus-critical execution. CLI/query/test code is NOT a finding.
- Check SDK version in go.mod before applying patterns (v0.47 removed GetSigners, v0.50 added ABCI 2.0, v0.53 deprecated ValidateBasic).
- Always use the Grep tool for searches, not bash grep. The reference file contains search patterns — use them directly with the Grep tool.
- Ignore cross-references to other resource files (e.g., links to IBC or COSMWASM patterns). Those patterns are covered by other scanning agents.
- Reject these rationalizations:
  - "ValidateBasic catches this" — deprecated and facultative since SDK v0.53
  - "Behind governance, so safe" — governance proposals can be malicious
  - "IBC counterparty is trusted" — any chain can open a channel
  - "Panic can't happen, input is validated" — trace the full call chain
  - "Rounding error is only a few tokens" — compounds over time, can be looped
  - "EVM precompile handles rollback" — many have incomplete rollback

SEVERITY:
- Critical (fund loss): signer mismatch, broken bookkeeping, AnteHandler bypass, bank keeper misuse, IBC token inflation, EVM/Cosmos desync, Merkle proof forgery, arithmetic overflow
- High (chain halt): non-determinism, ABCI panics, slow ABCI, non-deterministic IBC acks, consensus gaps, CacheContext event leak
- Medium (DoS): unbounded pagination, tx replay, missing validation, governance spam, rate limiting, circuit breaker bypass, storage key collisions
- Low (logic): rounding errors, stub handlers, event override, module ordering

OUTPUT — RETURN FORMAT:
Do NOT write any files. Return ALL findings and the summary in your response.

For each pattern, return one of:
  §NUM PATTERN_NAME: Not applicable — [one-line reason]
  §NUM PATTERN_NAME: FINDING (followed by the finding block below)

For each finding, include the full content using this template:

FINDING_FILE: {SEVERITY}-s{SECTION_NUM}-{kebab-description}.md
## [SEVERITY] Title
**Location**: `file:line`
**Description**: What the bug is and why it matters
**Vulnerable Code**: [snippet]
**Attack Scenario**: [numbered steps]
**Recommendation**: How to fix
**References**: [links to relevant advisories or building-secure-contracts]

You MUST report on ALL patterns in the reference file — do not skip any.

Exit: All scanning agents returned. Each reported on every pattern in their reference file.

Phase 3: Write Findings

After all scanning agents return, write finding files to the output directory (default .bughunt_cosmos/):

  1. Parse each agent's response for FINDING_FILE: blocks

  2. For each finding, Write the content to {OUTPUT_DIR}/{filename} using the filename from FINDING_FILE:

  3. Create the output directory first if it doesn't exist

Phase 4: Verify Completeness

After writing all findings, verify every pattern was assessed:

  1. Collect the summary lines (§NUM entries) returned by each agent

  2. Check pattern counts against expected totals:

    • core-scanner: 8 patterns (§1-9, excluding §8 legacy-only)

    • state-scanner: 13 patterns (§11-23)

    • advanced-scanner: 4 patterns (§24-27)

    • evm-scanner (if spawned): 10 patterns (§1-10)

    • ibc-scanner (if spawned): 16 patterns (§1-16)

    • cosmwasm-scanner (if spawned): 3 patterns (§1-3)

  3. If any pattern is missing from a summary, flag it and re-prompt that agent

  4. List all finding files written to the output directory with a Glob for *.md

Exit: All patterns accounted for. Finding files listed for the user.


Success Criteria

  • [ ] Discovery CLAUDE.md written with complete technical inventory and threat model

  • [ ] All scanning agents completed and reported on every pattern in their reference file

  • [ ] Pattern counts verified against expected totals (no patterns skipped)

  • [ ] All findings written to output directory as individual markdown files

  • [ ] Each finding file includes: severity, location, vulnerable code, attack scenario, recommendation


Resources

Files

resources/EVM_VULNERABILITY_PATTERNS.md

Cosmos EVM Vulnerability Patterns

Vulnerability patterns specific to Cosmos EVM chains (evmOS, Ethermint, Initia, Berachain, Sei, etc.). These chains run two execution runtimes (EVM + Cosmos SDK) with independent state that must stay in sync. This is the most frequently discovered vulnerability class in Cosmos EVM chains — 7+ findings across multiple chains, $7M+ in real losses. Referenced by SKILL.md.

1 EVM REVERT DOES NOT ROLLBACK COSMOS STATE

Description: Precompiles bridge EVM and Cosmos state machines. When a Solidity revert, try/catch, or out-of-gas (OOG) occurs, EVM state rolls back automatically, but Cosmos keeper writes made during the precompile call persist. An attacker wraps a precompile call in try/catch, triggers a revert after the Cosmos-side effect executes, and gets the EVM-side effect undone while keeping the Cosmos-side effect. Every Cosmos EVM chain is vulnerable until it implements snapshot-based atomic precompile wrappers.

Detection Patterns:

// VULNERABLE: Solidity try/catch around precompile call
// EVM state rolls back on revert, but Cosmos delegation persists
contract InfiniteDelegate {
    IStaking constant STAKING = IStaking(0x...1003);

    function exploit(address validator, uint256 amount) external {
        try this._delegate(validator, amount) {} catch {}
        // EVM: tokens refunded (revert undid the transfer)
        // Cosmos: delegation still exists (keeper write persisted)
        // Net effect: delegation increased without balance decreasing
    }

    function _delegate(address validator, uint256 amount) external {
        STAKING.delegate(validator, amount);
        revert();  // EVM state rolls back, Cosmos state does NOT
    }
}

What to Check:

  • [ ] ALL precompile Run() methods wrapped in atomic snapshot/revert (no partial execution on OOG or error)

  • [ ] EVM revert / try/catch / OOG propagates rollback to Cosmos keeper state — test with Solidity try/catch around every precompile call

  • [ ] IBC operations triggered via precompiles are atomic with the EVM transaction

References:


2 STATEDB.COMMIT() DURING PRECOMPILE EXECUTION

Description: Certain precompile calls (e.g., delegationTotalRewards) trigger StateDB.Commit(), writing state to permanent storage mid-execution. A subsequent revert only undoes cached in-memory state — permanent storage retains the committed state. This creates orphaned contracts with withdrawable balances. Exponential multiplication is possible: 1 ETH becomes 1,048,576 ETH in 20 loops.

Detection Patterns:

// VULNERABLE: Precompile triggers StateDB.Commit() (Finding 6)
// Calling certain precompiles caused StateDB.Commit() to write
// state to permanent storage. A subsequent revert only undoes
// cached in-memory state, but permanent storage retains the
// committed state.
// Result: Orphaned contracts with balances are accessible and withdrawable.

What to Check:

  • [ ] StateDB.Commit() is NEVER called during precompile execution (only at transaction finalization)

  • [ ] Precompile code paths audited for any indirect Commit() triggers (e.g., via keeper calls that flush caches)

  • [ ] StateDB journal entries cover all state modifications made by precompiles

Grep Patterns (use Grep tool with glob: "*.go" in x/):

  • StateDB|stateDB — then check results for commit context

  • func.*Run\(.*vm\.EVM — precompile Run methods

References:


3 PARTIAL PRECOMPILE EXECUTION (OOG)

Description: A precompile Run() performs multiple Cosmos state changes sequentially (e.g., transfer rewards then clear claimable counter). If execution runs out of gas between steps, early state changes persist while later ones are skipped. The attacker receives rewards but the claimable counter is never reset — repeat to drain the module.

Detection Patterns:

// VULNERABLE: Precompile Run() not atomic (Finding 20)
func (p DistributionPrecompile) Run(evm *vm.EVM, input []byte) ([]byte, error) {
    // Step 1: Transfer rewards to user (succeeds)
    k.bankKeeper.SendCoins(ctx, moduleAcc, userAddr, rewards)
    // Step 2: Clear claimable rewards (runs out of gas here!)
    k.SetClaimableRewards(ctx, userAddr, sdk.Coins{})
    // User received rewards but claimable counter never reset
    // Repeat to drain distribution module
}

What to Check:

  • [ ] Every precompile Run() is wrapped in an atomic execution wrapper (snapshot before, revert on any error including OOG)

  • [ ] No multi-step state mutations without atomicity guarantees

  • [ ] Gas estimation for precompile operations is accurate (underestimation enables OOG at attacker-chosen points)

Mitigation:

// SECURE: Wrap in atomic execution
func (p DistributionPrecompile) Run(evm *vm.EVM, input []byte) ([]byte, error) {
    return p.RunAtomic(evm, input, func(ctx sdk.Context) ([]byte, error) {
        // All operations atomic — snapshot + revert on any error including OOG
    })
}

References:


4 REVERTED EVM CALLS LEAVE COSMOS MESSAGES IN QUEUE

Description: When an EVM call dispatches a Cosmos message (e.g., IBC transfer) via a precompile, and the EVM call subsequently reverts, the dispatched Cosmos message remains in the execution queue. The Cosmos message executes despite the EVM revert, enabling IBC transfers (and other Cosmos-side effects) without corresponding EVM-side state changes.

Detection Patterns:

// VULNERABLE: Initia — dispatched Cosmos messages remain in execution queue
// even when the EVM call that dispatched them reverts (Finding 26b)
// Solidity try/catch wraps a call that dispatches IBC transfer via precompile
// Revert undoes EVM state but IBC transfer message still in Cosmos execution queue
// Result: IBC transfers execute despite explicit reversion

What to Check:

  • [ ] Cosmos message dispatch queue is cleared when EVM execution reverts

  • [ ] All Cosmos messages dispatched from precompiles are tracked in the EVM journal and rolled back on revert

  • [ ] Test: wrap every message-dispatching precompile call in Solidity try/catch with explicit revert — verify no Cosmos messages execute

References:


5 GAS LIMIT BYPASS VIA PRECOMPILE DISPATCH

Description: Solidity's call{gas: X}() restricts gas forwarded to an untrusted contract. But if that contract calls a precompile that dispatches a new Cosmos MsgCall, the new message gets the full parent transaction gas limit — not the restricted amount. This defeats gas-based reentrancy guards and any logic relying on gas limits to bound untrusted execution.

Detection Patterns:

// VULNERABLE: Initia — COSMOS_CONTRACT precompile bypasses gas restrictions (Finding 26c)
// Solidity call{gas: X}(untrustedContract) restricts gas
// But untrusted contract calls COSMOS_CONTRACT precompile to dispatch new MsgCall
// New MsgCall gets full parent transaction gas limit, not the restricted amount

What to Check:

  • [ ] Gas forwarding through precompile dispatch does not bypass caller-imposed gas limits

  • [ ] Precompile-dispatched messages inherit the remaining gas of the calling frame, not the transaction-level gas limit

  • [ ] Gas-based reentrancy guards are not the sole defense (combine with mutex/state guards)

References:


6 WRONG ROUTING IN MULTI-DENOM ERC20 OPERATIONS

Description: When processing multiple denominations in a loop, ERC20-related operations (burn, mint, community pool funding) accidentally use the full amount parameter (all denoms) instead of the individual coin being processed. If the loop contains both ERC20 and native denoms, the native denom amount is sent to the wrong destination on every iteration that hits the ERC20 path.

Detection Patterns:

// VULNERABLE: Initia — BurnCoins sends entire amount to community pool (Finding 26a)
// When burning ERC20 denominated coins in a loop,
// the function sends the full `amount` parameter (all denoms)
// instead of just the individual `coin` being processed
func (k Keeper) BurnCoins(ctx sdk.Context, amount sdk.Coins) error {
    for _, coin := range amount {
        if k.isERC20(coin.Denom) {
            // WRONG: sends ALL coins, not just this one
            k.communityPoolKeeper.FundCommunityPool(ctx, amount, moduleAddr)
        }
    }
}

What to Check:

  • [ ] Multi-denom operations in loops use the individual coin, not the full amount parameter

  • [ ] ERC20/native denom branching logic tested with mixed-denom inputs

  • [ ] Community pool / burn / mint amounts match the specific coin being processed

Mitigation:

// SECURE: Use the individual coin in the loop
func (k Keeper) BurnCoins(ctx sdk.Context, amount sdk.Coins) error {
    for _, coin := range amount {
        if k.isERC20(coin.Denom) {
            k.communityPoolKeeper.FundCommunityPool(ctx, sdk.NewCoins(coin), moduleAddr)
        } else {
            k.bankKeeper.BurnCoins(ctx, moduleName, sdk.NewCoins(coin))
        }
    }
}

References:


7 ETHERMINT ANTE HANDLER BYPASS (NESTED MESSAGES)

Description: Cosmos EVM chains add custom AnteHandler decorators for EVM-specific validation (gas price floors, tx type restrictions, EVM-specific fee checks). These decorators typically only inspect the outer message. An attacker wraps a blocked EVM message inside x/authz MsgExec or an x/group proposal — the inner message skips EVM-specific ante validation entirely.

Detection Patterns:

// VULNERABLE: AnteHandler only checks outer message type
func (d EthGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
    for _, msg := range tx.GetMsgs() {
        // Only checks outer msg — does NOT recurse into MsgExec.Msgs!
        if ethMsg, ok := msg.(*evmtypes.MsgEthereumTx); ok {
            if err := d.validateGas(ethMsg); err != nil {
                return ctx, err
            }
        }
    }
    return next(ctx, tx, simulate)
}

What to Check:

  • [ ] Custom EVM AnteHandlers recurse into x/authz MsgExec and x/group proposal inner messages

  • [ ] EVM-specific fee/gas validation applies to nested EVM messages, not just top-level

  • [ ] SDK MaxUnpackAnyRecursionDepth = 10 is not sufficient — semantic nesting (authz wrapping authz) must be handled by the ante handler itself

  • [ ] Integration tests submit EVM messages wrapped in MsgExec to verify they are validated

Mitigation:

// SECURE: Recurse into nested messages
func (d EthGasDecorator) checkMsg(msg sdk.Msg) error {
    if ethMsg, ok := msg.(*evmtypes.MsgEthereumTx); ok {
        return d.validateGas(ethMsg)
    }
    if exec, ok := msg.(*authz.MsgExec); ok {
        for _, inner := range exec.Msgs {
            var innerMsg sdk.Msg
            if err := d.cdc.UnpackAny(inner, &innerMsg); err != nil {
                return err
            }
            if err := d.checkMsg(innerMsg); err != nil {
                return err
            }
        }
    }
    return nil
}

References:


8 EVM HOOKS AND CROSS-MODULE INTERACTIONS

Description: Cosmos EVM chains use hooks (PostTxProcessing, PreTxProcessing) to synchronize EVM and Cosmos state after EVM transactions. The x/evm and x/erc20 modules fire these hooks on every EVM transaction. Bugs in hook logic — missing error propagation, state assumptions, reentrancy via hook callbacks — break the cross-module state invariant.

What to Check:

  • [ ] EVM hooks from x/evm and x/erc20 modules reviewed for correctness

  • [ ] Hook errors propagate correctly (a failed hook must revert the entire EVM transaction)

  • [ ] Hooks do not assume EVM state is finalized (it may still be in a cached context)

  • [ ] Cross-module interactions between x/evm, x/erc20, x/bank, and x/staking do not create circular dependencies or reentrancy

  • [ ] User interaction with module special addresses reviewed — EVM contracts should not be able to interact with Cosmos module accounts in unexpected ways


9 ETHEREUM ADDRESS VALIDATION

Description: Cosmos EVM chains handle two address formats: Bech32 (cosmos1...) and hex (0x...). The go-ethereum function common.HexToAddress() does NOT validate format and silently ignores errors — it returns a zero-padded address for any invalid input. Address mapping between the two formats must be bijective and validated.

Detection Patterns:

// VULNERABLE: HexToAddress does not verify format, ignores errors
addr := common.HexToAddress(userInput)
// "not_an_address" → 0x0000000000000000000000000000000000000000
// No error returned! Silently maps to zero address.

// VULNERABLE: Inconsistent address derivation
cosmosAddr := sdk.AccAddress(ethAddr.Bytes())  // Cosmos addr from ETH addr
ethAddr2 := common.BytesToAddress(cosmosAddr)   // Round-trip may not match

What to Check:

  • [ ] NOT using common.HexToAddress() for user-supplied input — use a validating function instead

  • [ ] Address conversion between Bech32 and hex is validated in both directions

  • [ ] Zero address (0x000...) is explicitly rejected where it should not be valid

  • [ ] EVM contract addresses derived from Cosmos module accounts are deterministic and documented

Mitigation:

// SECURE: Validate hex address format before conversion
func ValidateHexAddress(addr string) (common.Address, error) {
    if !common.IsHexAddress(addr) {
        return common.Address{}, fmt.Errorf("invalid hex address: %s", addr)
    }
    return common.HexToAddress(addr), nil
}

10 CROSS-CHAIN TRANSACTION REPLAY AND CHAIN ID

Description: Cosmos EVM chains use an epoch-based chain ID format (chainname_NNNN-1) where the numeric part maps to the Ethereum chain ID used in EVM transaction signing. If the chain ID epoch is not correctly parsed or enforced, transactions signed for one chain can be replayed on another. Nonce management differs between EVM (per-account incrementing) and Cosmos (sequence numbers) — mismatches enable replay or stuck transactions.

What to Check:

  • [ ] Chain ID epoch is correctly parsed and used as the EVM chain ID in ethermint/types/chain_id.go

  • [ ] EVM transactions are validated against the current chain ID (not just any valid chain ID)

  • [ ] Nonce management is synchronized between EVM and Cosmos account sequences

  • [ ] Chain upgrades that change the chain ID epoch correctly invalidate pending EVM transactions

  • [ ] eth_chainId RPC returns the correct value matching the Cosmos chain ID epoch


SUMMARY: COSMOS EVM BUG CLASSES
#PatternImpactKnown Incident / Reference
1EVM revert doesn't rollback Cosmos stateFund theft (infinite delegation/mint)Saga $7M, Finding 5/7
2StateDB.Commit() during precompileInfinite mint (exponential)Evmos, Finding 6
3Partial precompile execution (OOG)Module drainageGHSA-mjfq-3qr2-6g84, Finding 20
4Reverted EVM calls leave Cosmos msgsUnauthorized IBC transfersInitia, Finding 26b
5Gas limit bypass via precompile dispatchReentrancy guard defeatInitia, Finding 26c
6Wrong routing in multi-denom ERC20 opsFund misroutingInitia, Finding 26a
7Ethermint ante handler bypassValidation skip via nested msgsJump Crypto disclosure
8EVM hooks cross-module interactionsState desyncMultiple chains
9Ethereum address validationZero address injectiongo-ethereum HexToAddress
10Cross-chain tx replay / chain IDTransaction replayChain ID epoch parsing

GREP PATTERNS (ALL PATTERNS)

Use the Grep tool with glob: "*.go" in x/ for all searches below.

Precompile implementations:

  • func.*Run\(.*vm\.EVM — precompile Run methods

  • precompile|Precompile — precompile files

StateDB usage:

  • StateDB|stateDB — then check results for commit context

  • stateDB\.(Snapshot|RevertToSnapshot) — snapshot/revert usage

EVM hooks:

  • PostTxProcessing|PreTxProcessing|EvmHooks

ERC20 module:

  • isERC20|IsERC20|erc20 — ERC20 detection

  • RegisterERC20|RegisterCoin|ToggleConversion — token conversion

Address handling:

  • HexToAddress|IsHexAddress|BytesToAddress

Ante handlers:

  • AnteHandle|AnteDecorator — handler files

  • MsgEthereumTx|EthereumTx — EVM message type

Chain ID:

  • ChainID|ParseChainID|EpochNumber

Solidity patterns (use glob: "*.sol" in contracts/):

  • try|catch|revert — revert/try-catch patterns


References

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Trail of Bits
Publisher
Trail of Bits (Official)
Source
trailofbits/skills · plugins/building-secure-contracts/skills/cosmos-vulnerability-scanner · commit e4dd0bb
Licence
Creative Commons Attribution-ShareAlike 4.0 International (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Trail of Bits.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download cosmos-vulnerability-scanner.zip