How a CosmWasm contract gets compromised
CosmWasm contracts are Rust compiled to WebAssembly, running on Cosmos chains under an actor model: contracts do not call each other synchronously. They send messages. The runtime delivers messages in turn. Submessages allow a contract to react to the result of a previous message through a reply handler.
The reply-handler pattern is where most CosmWasm-specific bugs live. The IBC integration is where the cross-chain bugs live. Migration handlers are where the upgrade-authority bugs live. Each pattern below is one of those.
The audit methodology applies to CosmWasm the same way it applies to EVM. Read it first if you have not.
What's different from EVM
Three differences shape the audit work.
Message-based execution. A contract does not synchronously call another contract. It returns a Response that contains submessages; the runtime delivers them after the current call returns. State changes are committed only when the whole message tree completes successfully.
Reply handlers. A contract that wants to react to the result of a submessage registers a reply handler. The handler runs after the submessage settles (success or failure). The state visible at reply time includes the submessage's effects.
Migration handlers. A contract upgrade runs the new contract's migrate function against the old contract's state. The migrate handler can rewrite arbitrary state. Whoever can trigger migration (the admin) controls the contract's entire storage from that block on.
What we look at first
The admin field. Every CosmWasm contract has an optional admin who can trigger migration. A non-empty admin is custody over the contract. We name the admin, the threshold/multisig structure, and the path to revoking admin (set admin to none) if the protocol intended to.
The reply handlers. Which messages this contract sends with Reply set, which IDs the reply handlers process, what state the handlers read and write. The reply-handler boundary is the riskiest one in a CosmWasm audit.
The IBC entry points. If the contract is IBC-enabled, the channel-open, packet-receive, and packet-ack handlers are an external trust boundary. Bugs here are cross-chain bugs.
The governance integration. Cosmos chains have native governance modules that can call contracts. A contract that accepts privileged calls from governance must verify the caller is the governance module address, not just trust the message context.
The pattern catalog
Reply-handler reentrancy. A contract that sends submessages and reacts in a reply handler can be re-entered through the reply if the submessage CPIs back. The runtime's atomicity guarantee (all-or-nothing on the whole message tree) helps but does not eliminate logic errors where reply handlers assume the state they wrote in the original message has not been touched.
Submessage reply-on-error handling. A submessage can have ReplyOn::Always, Success, Error, or Never. A handler that processes Always but ignores the success/failure flag treats failures as successes. A handler with Never that depends on the submessage having succeeded is depending on something the runtime never tells it about.
Migration handler trust. The migrate function runs on the new code against the old state. If migrate is too permissive (rewrites arbitrary state without validation), the admin can do anything during an upgrade. If migrate is too strict (refuses to migrate state shapes the protocol intends to support), legitimate upgrades fail.
IBC packet trust. Packets arrive at the IBC entry point through the IBC module. The contract must validate the packet source, the channel, the destination port. A handler that trusts any IBC packet is trusting any IBC-connected chain.
IBC channel lifecycle. Channel open, channel close, channel close-confirm. Each step is callable by the IBC module. A contract that does not handle channel-close correctly can be locked into a state where users cannot withdraw funds locked under that channel. The IBC protocol has continued to evolve (IBC v2 simplifies the packet format and channel model relative to v1, and IBC-Lite is an emerging variant for chains that want a smaller surface). Production contracts in audit today target a mix; we identify which IBC variant the contract supports and audit only that surface, rather than treating the protocol as homogeneous.
Native module interaction. CosmWasm contracts can interact with native Cosmos modules (bank, staking, IBC, governance) through CosmosMsg. Each module has its own trust model. A contract that delegates authority to the staking module (granting it the right to stake on behalf of users) is extending trust to the validator set.
Block timestamp manipulation. Cosmos block times are not as predictable as Ethereum's; validators can produce blocks slightly out of order. A contract that depends on exact block timestamps for time-locks or randomness is exposed.
Address validation. CosmWasm contract addresses are bech32-encoded. Functions that accept user-supplied addresses must validate them. Addr::unchecked skips validation; api.addr_validate does not. We hunt every Addr::unchecked and verify the source is trusted.
Storage key collisions. CosmWasm storage uses key-value with namespaced keys. A library that uses a key the contract also uses (without namespacing) causes collisions. The cw-storage-plus library namespaces correctly; ad-hoc storage does not. The cw-utils library provides standard payment, expiration, and threshold helpers that production CosmWasm contracts lean on heavily; we audit the helper usage as carefully as the contract's own code, since most CosmWasm contracts share these dependencies.
Cosmos governance proposal exposure. Cosmos chains can authorize contract execution via on-chain governance proposals (gov-proposal-based migration, admin changes, or arbitrary calls authorized by the governance module). A contract that accepts a MsgExecuteContract originating from the governance module address is exposing itself to the validator set's voting outcome. We name the governance proposal types that can affect the contract and verify the contract's gates are appropriate for the threshold the chain's governance applies.
Gas limits and message fees. Cosmos chains have per-message gas limits. A contract that sends a submessage that requires too much gas hits the limit and the whole message tree reverts. Long-running migrations, complex reply handlers, and batched native calls all face this constraint.
What we audit on a CosmWasm contract
We audit:
- the admin field and the migration path
- every submessage's
Replysetting against the handler's behavior - every reply handler against the state changes it makes and assumes
- every IBC entry point against packet source and channel validation
- every
CosmosMsg::*for native-module trust - every
Addr::uncheckedfor source validation - storage key namespacing across all libraries the contract uses
- block-timestamp dependencies for manipulation exposure
The deliverable is the audit report described in our methodology.
Tools that earn their place
cosmwasm-check verifies a compiled contract against the CosmWasm runtime constraints (size, imports, allowed CosmWasm version).
cw-multi-test is a multi-contract test environment that lets the audit script complex message-passing scenarios in a unit test.
cosmwasm-vm is the runtime as a library; useful for advanced fuzzing and property-based testing.
Slither analogs for CosmWasm are immature. Most audit work is manual review of Rust source, with help from cargo audit for dependency vulnerabilities (it cross-references the Rust dependency tree against the RustSec Advisory Database) and clippy for general Rust hygiene. cargo audit runs against the same dependency-vulnerability source set that a Cargo project on any platform would use; the CosmWasm-specific risk it does not catch is in the runtime-import surface and the reply-handler patterns, which require manual review.
Protocol case anatomies. The CosmWasm production set has matured to the point where named protocols (cross-chain margin protocols on Osmosis, AMMs on Neutron and Stargaze, lending markets like Mars on Osmosis) are widely audited and their patterns documented. A new CosmWasm audit cross-references known protocol-class patterns: liquidation logic against established lending models, AMM math against established curve invariants, IBC-routed swaps against established channel-lifecycle patterns. Reinventing the wheel without checking the catalog is itself a finding.
What clean means
A clean CosmWasm audit means the reply handlers, migration authority, IBC trust, and native-module integration are sound under the threat model the contract states. It does not mean the underlying Cosmos chain's consensus or governance modules cannot act against the contract. Those are chain-level risks; we name them and constrain the contract's exposure where possible.