Cosmos Vulnerability Scanner
Trail of BitsOfficialPublished by Trail of Bits
- Skill
- Workflow
- Security
- CC-BY-SA-4.0
- No issues found
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
Download the skill as a ZIP:
https://autogineer.com/agent-skills/trailofbits/cosmos-vulnerability-scanner/downloadUnzip 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
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.
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.
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.modversions before applying patterns.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.
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:
Follow the Discovery workflow to explore the target codebase
Return the full CLAUDE.md content (the technical inventory and threat model) in its response
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 Name | Reference File | Scope |
|---|---|---|
core-scanner | VULNERABILITY_PATTERNS.md | §1-9: non-determinism, ABCI, signers, validation, handlers, ante security |
state-scanner | STATE_VULNERABILITY_PATTERNS.md | §11-23: bookkeeping, bank, pagination, events, tx replay, governance, arithmetic, encoding, deprecated modules |
advanced-scanner | ADVANCED_VULNERABILITY_PATTERNS.md | §24-27: storage keys, consensus validation, circuit breaker, crypto |
Spawn conditionally (in the same parallel message):
| Agent Name | Condition | Reference File |
|---|---|---|
evm-scanner | PLATFORM includes evm | EVM_VULNERABILITY_PATTERNS.md |
ibc-scanner | IBC_ENABLED is true | IBC_VULNERABILITY_PATTERNS.md |
cosmwasm-scanner | PLATFORM includes wasm | COSMWASM_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/):
Parse each agent's response for
FINDING_FILE:blocksFor each finding, Write the content to
{OUTPUT_DIR}/{filename}using the filename fromFINDING_FILE:Create the output directory first if it doesn't exist
Phase 4: Verify Completeness
After writing all findings, verify every pattern was assessed:
Collect the summary lines (§NUM entries) returned by each agent
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)
If any pattern is missing from a summary, flag it and re-prompt that agent
List all finding files written to the output directory with a
Globfor*.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
Discovery & CLAUDE.md: DISCOVERY.md
Core patterns (§1-9): VULNERABILITY_PATTERNS.md
State & module patterns (§11-23): STATE_VULNERABILITY_PATTERNS.md
Advanced patterns (§24-27): ADVANCED_VULNERABILITY_PATTERNS.md
IBC vulnerabilities: IBC_VULNERABILITY_PATTERNS.md
CosmWasm vulnerabilities: COSMWASM_VULNERABILITY_PATTERNS.md
EVM vulnerabilities: EVM_VULNERABILITY_PATTERNS.md
Building Secure Contracts:
building-secure-contracts/not-so-smart-contracts/cosmos/Cosmos SDK Docs: https://docs.cosmos.network/
CodeQL for Cosmos SDK: https://github.com/crypto-com/cosmos-sdk-codeql
Files
- ATTRIBUTION.mdAdded by AutoGineer975 B
- CHANGELOG.md12.6 KiB
- LICENSELicence file added by AutoGineer19.7 KiB
- SKILL.md10.7 KiB
- agents/openai.yaml256 B
- assets/trail-of-bits-mark.svg3.0 KiB
- resources/ADVANCED_VULNERABILITY_PATTERNS.md12.5 KiB
- resources/COSMWASM_VULNERABILITY_PATTERNS.md7.5 KiB
- resources/DISCOVERY.md2.9 KiB
- resources/EVM_VULNERABILITY_PATTERNS.md18.0 KiB
- resources/IBC_VULNERABILITY_PATTERNS.md27.5 KiB
- resources/STATE_VULNERABILITY_PATTERNS.md29.2 KiB
- resources/VULNERABILITY_PATTERNS.md26.4 KiB
resources/IBC_VULNERABILITY_PATTERNS.md
IBC Vulnerability Patterns & Audit Checks
IBC-specific vulnerabilities for Cosmos chains integrating ibc-go. 16 vulnerability patterns covering middleware bugs, channel/denom handling, Interchain Accounts misuse, reentrancy, and general IBC integration checks. Referenced by SKILL.md.
1 UNTRUSTED IBC COUNTERPARTY CHAIN
Description: An attacker can create a malicious chain and spoof IBC message fields. The counterparty chain controls the sender, memo, and other packet data fields. Any IBC middleware or hook that acts on these fields must validate against a channel/counterparty whitelist. With ICS-20 v2 forwarding (ibc-go v9+), a forwarded packet may originate from a chain several hops away with no direct trust relationship.
What to Check:
[ ] Chains that can connect are authorized via a channel/counterparty whitelist
[ ] IBC middleware and hooks that act on
sender,memo, or other packet data fields validate the source channel[ ] With ICS-20 v2 forwarding, multi-hop trust implications are considered (forwarded packets may originate from untrusted chains)
Grep Patterns (use Grep tool with glob: "*.go" in x/):
OnRecvPacket|OnAcknowledgementPacket— then check results forsenderormemousage
References:
2 UNSAFE LookupModuleByPort AND LookupModuleByChannel USAGE
Description: [ibc-go < v10 only] LookupModuleByPort and LookupModuleByChannel were problematic APIs in the IBC capability module. They were removed in v10 along with the capability module (#7239, #7252), replaced by a static port router (PortKeeper.GetRoute()). On older ibc-go versions, incorrect usage of these APIs can lead to wrong module routing.
What to Check:
[ ] If module has access to
ibckeeper,LookupModuleByPortandLookupModuleByChannelusages are carefully reviewed[ ] On ibc-go v10+, verify these APIs are no longer used and the static port router is used instead
Grep Patterns (use Grep tool with glob: "*.go" in x/):
LookupModuleByPort|LookupModuleByChannel
References:
3 MISSING IBC CHANNEL CLOSE VALIDATION
Description: If a user should NOT be able to close an IBC channel, the OnChanCloseInit callback must return an error. Failing to do so allows any user to close the channel, disrupting the IBC application. The transfer module explicitly rejects channel close as a reference pattern.
Detection Patterns:
// VULNERABLE: Missing or permissive channel close callback
func (im IBCModule) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error {
return nil // Allows anyone to close the channel!
}What to Check:
[ ]
OnChanCloseInitreturns an error if channels should not be closable by users[ ] Channel close behavior is explicitly tested
Mitigation:
// SECURE: Reject channel close
func (im IBCModule) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error {
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "channel close not allowed")
}4 INCORRECT IBC PACKET TIMEOUT HANDLING
Description: When an IBC packet times out or fails, the application must correctly refund tokens. On the source chain, escrowed tokens must be unescrowed; on the sink chain, burned vouchers must be minted back. See refundPacketToken in v8 (renamed to refundPacketTokens in v10 with InternalTransferRepresentation type). The core logic (source chain = unescrow, sink chain = mint back) is unchanged across versions.
What to Check:
[ ] Application handles packet timeout correctly — tokens are refunded on failed sends
[ ] Refund logic uses the same source/sink determination as the send path
[ ]
OnTimeoutPacketis implemented and tested for all packet types[ ] State changes from a failed send are fully rolled back
Grep Patterns (use Grep tool with glob: "*.go" in x/):
OnTimeoutPacket|refundPacketToken
5 INCORRECT IBC CHANNEL ORDERING TYPE
Description: ORDERED channels are closed on timeout — if a single packet times out, the entire channel is permanently closed. If message order doesn't matter, use UNORDERED to avoid this. Note: ORDERED_ALLOW_TIMEOUT was proposed but never merged into ibc-go.
What to Check:
[ ] Channel type (ORDERED vs UNORDERED) matches application invariants
[ ] If using ORDERED channels, the application handles channel closure on timeout gracefully
[ ] If message order doesn't matter, UNORDERED is used to avoid timeout-triggered channel closure
6 IBC TRANSFERS BREAKING INTERNAL BOOKKEEPING
Description: IBC transfers always mint/burn coins via x/bank. If a module maintains internal accounting (e.g., total deposited, collateral tracking), IBC transfers can silently break those invariants by moving tokens without going through the module's accounting path. Use blocklist, SendEnabled, or SendRestriction to control. In newer Cosmos SDK versions, SendRestriction is checked before deducting coins (SDK #20517), making it a more reliable defense. With ICS-20 v2 forwarding, tokens can arrive via unexpected multi-hop paths, amplifying bookkeeping risks.
What to Check:
[ ] IBC transfers cannot bypass internal bookkeeping for tokens managed by the module
[ ] Module uses blocklist,
SendEnabled, orSendRestrictionto prevent unauthorized IBC movement of managed tokens[ ] With ICS-20 v2 forwarding, multi-hop token arrival paths are considered
Grep Patterns (use Grep tool with glob: "*.go" in x/):
SendRestriction|BlockedAddr|SendEnabled
References:
7 NON-DETERMINISTIC JSON IN IBC ACKNOWLEDGEMENTS
Description: Custom IBC middleware that constructs or deserializes acknowledgement bytes using Go's encoding/json can produce non-deterministic results across different validators. Go's JSON unmarshaller does not guarantee consistent output for map key ordering, numeric precision for large numbers, unknown field handling, and Unicode normalization. If any middleware in the chain's IBC application stack introduces a custom ack format or manipulates ack bytes using standard JSON, different validators may compute different state transitions, halting the chain. Any user that can open an IBC channel can introduce this state — this is trivially exploitable.
Known incidents: ISA-2025-001 (GHSA-4wf3-5qj9-368v), ASA-2025-004 (GHSA-jg6f-48ff-5xrw) Affected versions: ibc-go >= v7 (earlier versions may also be affected) Patched in: v7.10.0, v8.7.0
Detection Patterns:
// VULNERABLE: Using encoding/json for IBC acknowledgements
func (m MyMiddleware) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, ack []byte) error {
var result map[string]interface{}
json.Unmarshal(ack, &result) // NON-DETERMINISTIC for maps!
newAck, _ := json.Marshal(result) // Different output across validators
// ...
}What to Check:
[ ] Custom IBC middleware does NOT produce acknowledgement bytes using
json.Marshalon types containing maps or floating-point numbers[ ] Acknowledgement serialization uses protobuf (not JSON), or a deterministic JSON marshaller (e.g.,
cosmossdk.io/x/tx/signing/aminojson)[ ] All middleware in the IBC stack uses deterministic serialization
[ ] Tests do not assume determinism from running on a single machine
Mitigation:
// SECURE: Use protobuf for acknowledgement serialization
func (m MyMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) ibcexported.Acknowledgement {
// Use the channeltypes ack types which serialize via protobuf
return channeltypes.NewResultAcknowledgement([]byte{byte(1)})
}Grep Patterns (use Grep tool with glob: "*.go" in x/):
json\.(Marshal|Unmarshal)— then check results forackoracknowledgementcontext
References:
8 PFM INVERTED ESCROW/MINT LOGIC
Description: In packet-forward-middleware, the moveFundsToUserRecoverableAccount() function (for nonrefundable forwarded packets) has the if/else branches for escrow vs. mint inverted relative to what SendTransfer() actually does. When a nonrefundable forward fails, the buggy code MINTS new tokens instead of UNESCROWING (or vice versa), inflating supply. An attacker sends tokens from Chain A to Chain B with a PFM forward to Chain C (marked nonrefundable). When the forward fails, PFM mints new tokens instead of unescrowing. The attacker sends the minted vouchers back to Chain A, draining A's escrow of real tokens. The attack is repeatable: each round inflates supply by the transfer amount.
Detection Patterns:
In relay.go SendTransfer():
if HasPrefix(sourcePort, sourceChannel) -> BURN
else (!HasPrefix) -> ESCROW
In WriteAcknowledgementForForwardedPacket() [CORRECT, non-nonrefundable path]:
if !HasPrefix -> tokens were ESCROWED -> code UNESCROWS from escrow [correct]
else HasPrefix -> tokens were BURNED -> code MINTS back [correct]
In moveFundsToUserRecoverableAccount() [BUGGY, nonrefundable path]:
if !HasPrefix -> tokens were ESCROWED -> code MINTS (WRONG!)
else HasPrefix -> tokens were BURNED -> code UNESCROWS (WRONG!)What to Check:
[ ] Every code path that reverses a transfer uses the same source/sink logic (
HasPrefix) as the original send[ ] Nonrefundable forwarding paths have explicit tests comparing escrow/mint direction against the refundable path
[ ] PFM is fuzz-tested with various denom trace configurations
Mitigation:
// SECURE: Verify source/sink logic is consistent across all refund paths
// The escrow/mint decision in error-handling paths must mirror SendTransfer():
// !HasPrefix (escrowed on send) -> UNESCROW on refund
// HasPrefix (burned on send) -> MINT on refundGrep Patterns (use Grep tool with glob: "*.go" in x/):
HasPrefix|SenderChainIsSource|ReceiverChainIsSource— source/sink logicnonrefundable|Nonrefundable— nonrefundable forwarding
9 ICS-20 V2 MULTI-TOKEN PARTIAL RECEIVE
Description: ICS-20 v2 allows sending multiple tokens in a single packet. The onRecvPacket function processes them sequentially in a for loop. If token N fails (e.g., insufficient escrow for unescrow), the loop breaks and returns an error acknowledgement. However, tokens 1..N-1 have already been minted/unescrowed on the receiver chain and are NOT rolled back. The sender chain then receives the error ack and calls refundTokens, which refunds ALL tokens — including the ones that were successfully delivered to the receiver. Tokens end up existing on both chains simultaneously, created from nothing. The ICS-20 v2 spec pseudocode itself contains this bug — implementers who faithfully translate the spec inherit it.
Detection Patterns:
// VULNERABLE: Non-atomic multi-token processing
func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error {
var data types.FungibleTokenPacketDataV2
// ...
for _, token := range data.Tokens {
// Each token modifies state immediately!
if err := k.processToken(ctx, token); err != nil {
return err // Tokens 1..N-1 already committed, no rollback
}
}
return nil
}What to Check:
[ ] Multi-token
onRecvPacketis wrapped inCacheContextto make all operations atomic[ ] State is only committed if ALL tokens process successfully
[ ] Tests cover packets where the Nth token fails for all values of N (not just happy path or first-token-fails)
[ ] The ICS-20 v2 spec pseudocode itself contains this bug — verify the implementation does NOT faithfully copy it
Mitigation:
// SECURE: Wrap multi-token processing in CacheContext
func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error {
var data types.FungibleTokenPacketDataV2
// ...
cacheCtx, writeFn := ctx.CacheContext()
for _, token := range data.Tokens {
if err := k.processToken(cacheCtx, token); err != nil {
return err // Discard all cached writes
}
}
writeFn() // Commit only if ALL tokens succeeded
return nil
}10 UNPERMISSIONED IBC CHANNEL OPENING
Description: By default, anyone can open an IBC channel to any chain. If a chain's IBC application doesn't properly validate channel parameters (version, ordering, counterparty), a malicious actor can open channels with unexpected configurations. This was the precondition for the non-deterministic JSON ack vulnerability (§7) — "any user that can open an IBC channel can introduce this state."
Detection Patterns:
// VULNERABLE: No validation in channel open callbacks
func (im IBCModule) OnChanOpenInit(ctx sdk.Context, order channeltypes.Order,
connectionHops []string, portID string, channelID string,
chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty,
version string) (string, error) {
return version, nil // Accepts ANY version, ordering, counterparty!
}What to Check:
[ ]
OnChanOpenInit/OnChanOpenTryimplement strict version and ordering checks[ ] Channel opening is permissioned (governance-gated) for sensitive applications
[ ] IBC application version strings are validated against an allowlist
[ ] Data from the counterparty chain is never trusted without validation
[ ] Unexpected port bindings are rejected
Mitigation:
// SECURE: Strict validation in channel open
func (im IBCModule) OnChanOpenInit(ctx sdk.Context, order channeltypes.Order,
connectionHops []string, portID string, channelID string,
chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty,
version string) (string, error) {
if order != channeltypes.UNORDERED {
return "", errorsmod.Wrapf(channeltypes.ErrInvalidChannelOrdering,
"expected %s, got %s", channeltypes.UNORDERED, order)
}
if version != types.Version {
return "", errorsmod.Wrapf(types.ErrInvalidVersion,
"expected %s, got %s", types.Version, version)
}
return version, nil
}Grep Patterns (use Grep tool in x/):
OnChanOpenInit|OnChanOpenTry
11 IBC DENOM / VOUCHER CONFUSION
Description: IBC denomination traces encode the full path a token has traveled. The ibc/HASH format hides the actual trace, and developers often fail to validate that a received denom is legitimate. Key concepts that are frequently confused: Source zone (token native to sending chain — escrowed on sender, minted as voucher on receiver), Sink zone (token returning to origin — voucher burned on sender, unescrowed on receiver), Trace path (transfer/channel-0/transfer/channel-1/uatom — encodes every hop), Hashed denom (ibc/27394FB092D2ECCD56... — SHA256 hash of the trace path). In ICS-20 v2, MsgSendPacket allowed users to specify IBCDenom() (the hashed form) instead of requiring the full trace, letting users bypass trace validation (cosmos/ibc-go#7848). Before ibc-go v9, FungibleTokenPacketData JSON unmarshalling silently accepted unknown fields, allowing packet manipulation (cosmos/ibc-go#6215).
Known issue: cosmos/ibc-go#7848
What to Check:
[ ] Full denom trace is validated, not just the base denomination
[ ] Denom whitelists are implemented for sensitive operations (collateral, governance)
[ ] Security model of each IBC path is documented (which chains are trusted)
[ ] Unknown fields in packet data unmarshalling are rejected
[ ] DEXes/lending protocols do NOT treat
ibc/HASH_Aandibc/HASH_B(both with baseuatom) as equivalent[ ]
uatomarriving viachannel-0anduatomarriving viachannel-1are treated as DIFFERENT tokens (different security properties)
Grep Patterns (use Grep tool with glob: "*.go" in x/):
IBCDenom|DenomTrace|GetFullDenomPath— denom trace handlingibc/— then check results fordenom,token, ortransfercontext
12 MISSING IBC RATE LIMITING
Description: Without rate limiting, a single exploit can drain an entire escrow in one block. Osmosis's rate limiting was explicitly credited with slowing down potential damage from the $126M reentrancy bug (ASA-2024-007).
What to Check:
[ ] Per-channel, per-denom, or aggregate rate limits are implemented on IBC transfers
[ ] Both inflows AND outflows are rate limited
[ ] Rate limits are set based on percentage of total supply, not absolute amounts
[ ] Channel opening itself is rate limited
[ ] Rate limit hits are monitored as an early warning system
[ ] Rate limits are governance-adjustable
Grep Patterns (use Grep tool in x/):
RateLimit|rate_limit|ratelimit
References:
13 ICA HOST ALLOW-ALL CONFIGURATION
Description: The Interchain Accounts (ICA) host module, when enabled, accepts a parameter allow_messages that controls which message types can be executed by remote controller chains. The default genesis configuration sets this to ["*"] — allowing ALL message types. If a chain enables ICA host with "*" and any other chain has a controller account on it, that controller chain can execute any message on the host chain, including governance proposals, staking operations, and module-specific messages. A chain may have ICA host enabled in its genesis JSON without the host keeper actually being wired, giving a false sense of security that disappears if the keeper is later connected (cosmos/ibc-go#6324).
Detection Patterns:
// VULNERABLE: Default genesis allows all messages
"host_genesis_state": {
"params": {
"host_enabled": true,
"allow_messages": ["*"]
}
}What to Check:
[ ]
allow_messagesis set to a minimal whitelist — NEVER"*"in production[ ] Controller chains that have accounts on the host are audited
[ ] ICA host enablement is governance-gated
[ ] A chain does not have ICA host enabled in genesis JSON without the host keeper actually being wired (false sense of security — cosmos/ibc-go#6324)
Mitigation:
// SECURE: Minimal whitelist
"host_genesis_state": {
"params": {
"host_enabled": true,
"allow_messages": [
"/cosmos.bank.v1beta1.MsgSend",
"/cosmos.staking.v1beta1.MsgDelegate"
]
}
}Grep Patterns (use Grep tool in x/):
allow_messages|AllowMessageswithglob: "*.{go,json}"— ICA allow listRegisterInterchainAccount|SendTx— ICA usage
References:
14 ICA CHANNEL ORDERING BACKWARDS COMPATIBILITY
Description: In ibc-go v7.5.0+, the default channel ordering for MsgRegisterInterchainAccount changed from ORDER_ORDERED to ORDER_UNORDERED. Older ibc-go versions only support ORDER_ORDERED for ICA channels. If a chain upgrades to ibc-go >= 7.5.0 and tries to open an ICA channel to a chain running an older version, the channel open will fail silently or explicitly. Additionally, ICA channel upgrades that change the ordering (ordered to unordered or vice versa) are explicitly disallowed by a guard that had to be added after the fact (cosmos/ibc-go#5415), meaning chains that performed such upgrades before the guard could have broken ICA functionality.
What to Check:
[ ] Channel ordering is explicitly pinned when upgrading ibc-go versions
[ ] ICA functionality is tested against counterparty chains running older ibc-go
[ ] ICA channel states are monitored after upgrades
References:
15 ICA AUTHENTICATION MODULE MISSING OR MISCONFIGURED
Description: ICA provides two entry points (RegisterInterchainAccount and SendTx) that are NOT exposed to end users directly. They must be gated by a custom "Authentication module" that controls who can use ICA. If the authentication module is missing, misconfigured, or overly permissive, any user may be able to register interchain accounts or submit transactions through them. The ICA spec (ICS-27) leaves the authentication module's design entirely to the chain developer. The informal systems audit noted: "The requirements and the API between the authentication and the ICA modules are not clearly specified."
What to Check:
[ ] A custom authentication module gates ICA usage
[ ]
RegisterInterchainAccountis restricted (governance, whitelisted addresses)[ ] Each
SendTxcall validates the caller is authorized for the specific interchain account[ ] ICA is NOT assumed to have built-in access control (it does not)
16 IBC REENTRANCY / CEI VIOLATIONS
Description: IBC's callback architecture (hooks, middleware) introduces external execution points between internal state operations. If a callback executes before internal state is finalized (e.g., packet commitment deleted), recursive re-entry is possible. This is a classic checks-effects-interactions (CEI) violation. The OnTimeoutPacket callback in ibc-go executed before the packet commitment was deleted — a malicious CosmWasm contract could re-enter via submessages since the commitment still existed. This class caused $6.4M in real losses and $150M+ at risk.
Known incidents: ASA-2024-007 ($150M+ at risk, patched April 2024), Terra IBC hooks ($6.4M stolen, July 2024 — chain had accidentally reintroduced the patched vulnerability during an upgrade)
Affected versions: ibc-go < v4.6.0, < v5.4.0, < v6.3.0, < v7.4.0, < v8.2.0
Detection Patterns:
// VULNERABLE: Callback before state finalization (CEI violation)
func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error {
// 1. CHECK: Verify packet commitment exists
commitment := k.GetPacketCommitment(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence)
// 2. INTERACTION: Execute callback (ibc-hooks invokes CosmWasm contract)
// Malicious contract returns another MsgTimeout as submessage
// Commitment still exists → re-entry succeeds!
k.callbacks.OnTimeoutPacket(ctx, packet)
// 3. EFFECT: Delete commitment (too late — already re-entered)
k.DeletePacketCommitment(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence)
return nil
}// SECURE: Effects before interactions (CEI pattern)
func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet) error {
// 1. CHECK
commitment := k.GetPacketCommitment(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence)
// 2. EFFECT: Delete commitment BEFORE callback
k.DeletePacketCommitment(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence)
// 3. INTERACTION: Now callback cannot re-enter (commitment gone)
k.callbacks.OnTimeoutPacket(ctx, packet)
return nil
}What to Check:
[ ] ibc-go version is patched (>= v4.6.0, v5.4.0, v6.3.0, v7.4.0, v8.2.0)
[ ] ALL IBC callbacks (OnRecvPacket, OnAcknowledgementPacket, OnTimeoutPacket) follow CEI: state mutation BEFORE external callbacks
[ ] Custom IBC middleware and hooks do NOT introduce new callback-before-finalization patterns
[ ] If the chain has been upgraded, verify the patch was NOT accidentally reverted (Terra re-introduced the vulnerability during a June 2024 upgrade)
[ ] CosmWasm-enabled chains with ibc-hooks middleware are at highest risk — CosmWasm submessages enable recursive re-entry
[ ] Rate limiting (§12) is implemented as defense-in-depth even with patched ibc-go
Vulnerable chain requirements: IBC-enabled + vulnerable ibc-go version + CosmWasm-enabled with permissionless uploads + ibc-hooks middleware wrapping ICS-20.
Two attack vectors:
Native token theft: Drain all tokens from ICS-20 escrow accounts
Infinite IBC token minting: Mint unbacked IBC tokens, bridge them back to original chains
Grep Patterns (use Grep tool with glob: "*.go" in x/):
OnTimeoutPacket|OnAcknowledgementPacket|OnRecvPacket— IBC callbacksDeletePacketCommitment— verify commitment deletion happens BEFORE callback invocationibc-hooks|ibchooks— hooks middleware presence
References:
SUMMARY: MOST DANGEROUS PATTERNS
| # | Pattern | Category | Known Incident / Reference |
|---|---|---|---|
| 1 | Untrusted IBC counterparty chain | Channel | GHSA-5jgq-x857-p8xw |
| 2 | Unsafe LookupModuleByPort/LookupModuleByChannel | Channel | ibc-go#71 |
| 3 | Missing IBC channel close validation | Channel | — |
| 4 | Incorrect IBC packet timeout handling | Channel | — |
| 5 | Incorrect IBC channel ordering type | Channel | — |
| 6 | IBC transfers breaking internal bookkeeping | Denom | SDK#20517 |
| 7 | Non-deterministic JSON in IBC ack middleware | Middleware | ISA-2025-001, ASA-2025-004 |
| 8 | PFM inverted escrow/mint (nonrefundable) | Middleware | PoC available |
| 9 | ICS-20 v2 multi-token partial receive inflation | Middleware | PoC available |
| 10 | Unpermissioned IBC channel opening | Channel | Precondition for ISA-2025-001 |
| 11 | IBC denom / voucher confusion | Denom | ibc-go#7848 |
| 12 | Missing IBC rate limiting | Defense | Would have limited $126M exploit |
| 13 | ICA host allow-all ("*") configuration | ICA | Default genesis config |
| 14 | ICA channel ordering backwards compat | ICA | ibc-go#6714 |
| 15 | ICA authentication module missing | ICA | ICS-27 audit finding |
| 16 | IBC reentrancy / CEI violations | Reentrancy | ASA-2024-007, Terra $6.4M exploit |
References
IBC-Go Security Advisories: https://github.com/cosmos/ibc-go/security/advisories
IBC-Go Audit Reports: https://docs.cosmos.network/ibc/v8.5.x/security-audits
Asymmetric Research: "Cosmos IBC Reentrancy Infinite Mint" — https://blog.asymmetric.re/cosmos-ibc-reentrancy-infinite-mint/
Jump Crypto: "Huckleberry: IBC Event Hallucinations" — https://jumpcrypto.com/resources/huckleberry-ibc-event-hallucinations
Cosmos Forum: IBC Security Advisories — https://forum.cosmos.network/c/security/
Osmosis Rate Limits: https://www.range.org/blog/ibc-rate-limits-introduction-and-state-of-the-art-1-3
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 or Trail of Bits.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download cosmos-vulnerability-scanner.zip