Agent skill
cosmos-scanner
Use when the user wants to audit Cosmos SDK modules or CosmWasm smart contracts, scan IBC protocol interactions for relay, channel, or packet vulnerabilities, review Cosmos Go modules for state machine exploits, or analyze cross-chain message handling in the Cosmos ecosystem.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/cosmos-scanner
SKILL.md
Cosmos / CosmWasm Security Scanner
Security scanner for Cosmos SDK modules (Go), CosmWasm smart contracts (Rust/WASM), and Inter-Blockchain Communication (IBC) protocol interactions.
Language & Runtime
| Attribute | Value |
|---|---|
| Chain | Cosmos Hub, Osmosis, Juno, Neutron, Injective, Sei, + 60 app-chains |
| Smart Contract Language | Rust (compiled to WASM) |
| SDK Language | Go (custom Cosmos SDK modules) |
| VM | CosmWasm (WASM-based) |
| Token Standard | CW20 (fungible), CW721 (NFT), CW1155 (multi-token) |
| Key Framework | cosmwasm-std, Cosmos SDK |
| Storage Model | Key-value store (binary prefixed maps) |
| Gas Model | Gas consumed per operation, configurable per chain |
Detection Capabilities
| Category | Detection | Severity |
|---|---|---|
| Authorization | Missing info.sender check on Execute handlers |
Critical |
| Authorization | Keeper function callable without proper auth (SDK modules) | Critical |
| Authorization | AuthZ overly broad grants enabling privilege escalation | High |
| IBC | Packet source/destination validation missing | Critical |
| IBC | Channel ordering assumption violation | High |
| IBC | Timeout and acknowledgement handling errors | High |
| State | Unbounded range() iteration (gas DoS) |
High |
| State | Iterator invalidation during mutation | High |
| State | Storage key collision in multi-contract systems | Medium |
| Cross-Contract | SubMessage reply handler not checking msg_id |
High |
| Cross-Contract | Bank send reentrancy via SubMessage reply | Medium |
| Math | Uint128/Uint256 overflow (panics in debug, wraps in release) |
High |
| Math | Decimal256 precision loss in rate calculations |
Medium |
| Governance | Parameter manipulation via governance proposal | Medium |
| Governance | Admin key not removable (centralization) | Medium |
| BlockHooks | BeginBlocker/EndBlocker gas consumption DoS (SDK modules) | High |
| Migration | migrate() entry point without access control |
Critical |
Architecture Model: CosmWasm Contracts
┌────────────────────────────────────────────────┐
│ CosmWasm Contract Entry Points │
├────────────┬───────────┬───────────┬───────────┤
│ instantiate │ execute │ query │ migrate │
│ (once) │ (state) │ (read) │ (upgrade) │
└────────────┴───────────┴───────────┴───────────┘
│ │
State (Items, Maps, SnapshotMaps) SubMessages
│ │
Storage (KV Store) Reply Handler
Entry Point Security Model
| Entry Point | info.sender |
State Access | Security Focus |
|---|---|---|---|
instantiate |
Contract deployer | Write | Set admin, validate config |
execute |
Transaction signer | Write | Primary attack surface |
query |
Not available | Read-only | Gas DoS, expensive computation |
migrate |
Contract admin | Write | Must check authorization |
reply |
Contract itself | Write | SubMessage result handling |
sudo |
Chain governance | Write | Privileged chain operations |
Notable Cosmos/CosmWasm Vulnerabilities
| Incident | Chain | Issue | Impact |
|---|---|---|---|
| Osmosis LP bug (2022) | Osmosis | Rounding error in LP share calculation | $5M at risk (white-hat) |
| Juno whale governance (2022) | Juno | Governance used to confiscate tokens | Governance centralization debate |
| Terra UST depeg (2022) | Terra | Algorithmic stablecoin design flaw | ~$40B market value lost |
| Wormhole bridge (2022) | Multi | Guardian signature verification bypass | $320M stolen |
| CW20 unlimited mint | Various | Missing admin check on mint execute | Token inflation |
| IBC race condition | Various | Packet ordering assumption violated | Token duplication |
Key Vulnerability Patterns
1. Missing info.sender Check
// VULNERABLE: Anyone can call
pub fn execute_withdraw(
deps: DepsMut,
_info: MessageInfo, // sender not checked!
amount: Uint128,
) -> Result<Response, ContractError> {
// Withdraws funds without checking who's requesting
let msg = BankMsg::Send {
to_address: "attacker".to_string(),
amount: vec![Coin { denom: "uatom".to_string(), amount }],
};
Ok(Response::new().add_message(msg))
}
// SAFE: Validates caller
pub fn execute_withdraw(
deps: DepsMut,
info: MessageInfo,
amount: Uint128,
) -> Result<Response, ContractError> {
let config = CONFIG.load(deps.storage)?;
if info.sender != config.admin {
return Err(ContractError::Unauthorized {});
}
// Proceed with withdrawal...
}
2. Unbounded State Iteration
// VULNERABLE: Iterates ALL entries — gas DoS as state grows
pub fn query_all_balances(deps: Deps) -> StdResult<Vec<(Addr, Uint128)>> {
let result: Vec<_> = BALANCES
.range(deps.storage, None, None, Order::Ascending)
.collect::<StdResult<Vec<_>>>()?; // Unbounded!
Ok(result)
}
// SAFE: Paginated with limit
pub fn query_balances(
deps: Deps,
start_after: Option<Addr>,
limit: Option<u32>,
) -> StdResult<Vec<(Addr, Uint128)>> {
let limit = limit.unwrap_or(30).min(100); // Cap at 100
let start = start_after.map(Bound::exclusive);
let result: Vec<_> = BALANCES
.range(deps.storage, start, None, Order::Ascending)
.take(limit as usize)
.collect::<StdResult<Vec<_>>>()?;
Ok(result)
}
3. SubMessage Reply Handler Bug
// VULNERABLE: Reply handler doesn't check which SubMessage triggered it
#[entry_point]
pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
// Assumes all replies are from the token transfer SubMessage
// But could be from any SubMessage!
handle_transfer_reply(deps, msg)
}
// SAFE: Checks reply ID
const TRANSFER_REPLY_ID: u64 = 1;
const MINT_REPLY_ID: u64 = 2;
#[entry_point]
pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
match msg.id {
TRANSFER_REPLY_ID => handle_transfer_reply(deps, msg),
MINT_REPLY_ID => handle_mint_reply(deps, msg),
_ => Err(ContractError::UnknownReplyId { id: msg.id }),
}
}
Resources
- CosmWasm Patterns
- IBC Security
Workflows
- CosmWasm Audit
Error Code Reference
Common Cosmos SDK, CosmWasm, and IBC error codes encountered during audits.
CosmWasm Standard Errors
| Error Type | Error Name | Meaning |
|---|---|---|
StdError::NotFound |
NotFound { kind } |
Queried item not found in storage |
StdError::InvalidBase64 |
InvalidBase64 { msg } |
Invalid base64 encoding in message |
StdError::InvalidUtf8 |
InvalidUtf8 { msg } |
Invalid UTF-8 in string conversion |
StdError::Overflow |
Overflow { source } |
Arithmetic overflow in Uint128/Uint256 operations |
StdError::DivideByZero |
DivideByZero { source } |
Division by zero in math operation |
StdError::ConversionOverflow |
ConversionOverflow { source } |
Type conversion exceeds target range |
StdError::GenericErr |
GenericErr { msg } |
Catch-all error — check msg for specifics |
Cosmos SDK Module Errors
| Module | Codespace | Error Code | Meaning |
|---|---|---|---|
bank |
bank |
5 |
Insufficient funds for send |
bank |
bank |
8 |
Send disabled for denom |
staking |
staking |
5 |
Validator not found |
staking |
staking |
7 |
Delegation not found |
staking |
staking |
12 |
Insufficient shares for undelegation |
auth |
auth |
4 |
Insufficient fee |
auth |
auth |
9 |
Signature verification failed |
gov |
gov |
3 |
Unknown proposal |
gov |
gov |
5 |
Inactive proposal — voting period ended |
IBC Protocol Errors
| Module | Error Code | Meaning |
|---|---|---|
channel |
5 |
Channel not found |
channel |
11 |
Packet already received — replay protection |
channel |
17 |
Packet timeout — message expired |
connection |
5 |
Connection not found |
transfer |
3 |
Invalid denomination trace |
transfer |
6 |
Receive disabled on this channel |
client |
6 |
Client state not found |
client |
9 |
Consensus state not found |
Troubleshooting
| Issue | Likely Cause | Solution |
|---|---|---|
| IBC message handling vulnerabilities missed | Scanner only checks contract logic, not IBC layer | Load resources/ibc-security.md and audit ibc_packet_receive / ibc_packet_ack handlers |
| CosmWasm reply handler issues not detected | Scanner doesn't follow submessage flow | Trace all SubMsg with ReplyOn::Success/ReplyOn::Error and match reply IDs |
| State machine exploit not flagged | Scanner checks individual messages, not sequences | Analyze multi-message transaction flows for state inconsistencies |
| Missing sudo handler audit | Scanner focuses on execute/query only | Check sudo() entry point — often used for privileged chain-level operations |
| Gas griefing not detected | Scanner doesn't model gas costs | Flag unbounded loops/iterations in execute and query handlers |
| Cross-contract call risks missed | Scanner doesn't trace inter-contract calls | Map all WasmMsg::Execute and WasmQuery::Smart calls to external contracts |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?