Skip to content
Security
Skill

/cosmos-sdk-module-safety

L1 trigger - audits Cosmos-SDK / CometBFT modules for consensus non-determinism, unmetered ABCI hooks, signer/state mismatches, module-account bookkeeping breaks, sdk.Dec rounding, ABCI-path panics, unregistered Msg handlers, and fee/gas overflow.

From plugin
plamen
276160 skills12 agents4 commands
Install
$ npx -y skills add PlamenTSV/plamen --skill cosmos-sdk-module-safety --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/cosmos-sdk-module-safety

Context preview

The summary Claude sees to decide when to auto-load this skill.

L1 trigger - audits Cosmos-SDK / CometBFT modules for consensus non-determinism, unmetered ABCI hooks, signer/state mismatches, module-account bookkeeping breaks, sdk.Dec rounding, ABCI-path panics, unregistered Msg handlers, and fee/gas overflow.

SKILL.md

cosmos-sdk-module-safety.SKILL.md
name: "cosmos-sdk-module-safety"
description: "L1 trigger - audits Cosmos-SDK / CometBFT modules for consensus non-determinism, unmetered ABCI hooks, signer/state mismatches, module-account bookkeeping breaks, sdk.Dec rounding, ABCI-path panics, unregistered Msg handlers, and fee/gas overflow."

Injectable Skill: Cosmos-SDK / CometBFT Module Safety

> **L1 trigger**: `L1_PATTERN=true` AND `COSMOS_SDK` (cosmos-sdk / cometbft / tendermint / `x/` modules detected) > **Inject Into**: `depth-consensus-invariant`, `depth-state-trace` > **Language**: Go (Cosmos-SDK) > **Finding prefix**: `[COS-N]` > **Status**: v0.1

Orchestrator Decomposition Guide

  • Sections 1, 2, 6, 7: depth-consensus-invariant (determinism, ABCI-hook metering, ABCI panics, Msg routing — all chain-halt / safety class)
  • Sections 3, 4, 5, 8: depth-state-trace (signer/state authority, module-account invariant, Dec rounding, fee/gas overflow — all accounting / authorization class)
  • A single bug can span both lenses; record it once and cross-reference.

When This Skill Activates

Recon classifies the target as a Cosmos-SDK / CometBFT application chain or module set (`go.mod` requires `cosmossdk.io/...`, `github.com/cosmos/cosmos-sdk`, `github.com/cometbft/cometbft`, `github.com/tendermint/tendermint`, or the tree has `x/<module>/keeper`, `x/<module>/types`, `abci.go`, `module.go`). Cosmos app-chain bugs are predominantly **consensus-halting** (every validator must compute byte-identical state) and **accounting** (module accounts must reconcile) — both are in scope for Plamen L1 audits. Severity baseline is Medium; chain-halt / fork and fund-loss classes upgrade to High/Critical per `docs/l1-mode/severity-matrix.md`.

A Cosmos state-transition path is any code reachable from a `Msg` handler (`msgServer` methods), `BeginBlock`, `EndBlock`, `InitGenesis`, `EndBlocker`, `PreBlocker`, or an AnteHandler/PostHandler that mutates committed state. Everything in those paths runs on **every validator** and MUST be deterministic and panic-safe.

1. Non-Determinism in State-Transition Paths

**Check**: No state-transition path may depend on per-node, wall-clock, or unordered data. Two honest validators replaying the same block MUST compute the same app hash; any divergence forks or halts the chain.

**Methodology**: 1. From `caller_map.md` / `function_summary.md`, enumerate every function reachable from a `Msg` handler, `BeginBlock(er)`, `EndBlock(er)`, `PreBlocker`, `InitGenesis`, or Ante/Post handler. These are the consensus-critical set. 2. For each, grep / inspect for non-deterministic sources:

  • **Map-range iteration without sort**: `for k := range <map>` or `for k, v := range <map>` where iteration order affects writes, accumulation order, or emitted state. Go randomizes map iteration order per process. Fix pattern is a sorted key slice (`maps.Keys` + `slices.Sort`) before ranging. Flag any range-over-map in the consensus set that feeds a state write or running total.
  • **Wall clock**: `time.Now()`, `time.Since(`, `time.Tick`, `os.Getenv` — block time must come from `ctx.BlockTime()` / `ctx.BlockHeader().Time`, never the OS clock.
  • **Randomness**: `math/rand`, `crypto/rand`, `rand.Intn`, unseeded or per-node-seeded RNG in a handler.
  • **Floating point**: `float32` / `float64` arithmetic, `math.Pow`, `math.Sqrt` on consensus values — float results are not guaranteed bit-identical across platforms; use `sdkmath.LegacyDec` / `big.Int`.
  • **`unsafe.`**, `reflect`-driven ordering, goroutines/channels whose completion order affects state, and `select` over multiple ready channels.

3. For each hit, confirm the value actually feeds committed state (app hash). A non-deterministic value used only for a log line is not a finding; one used for a balance, a winner selection, an iteration order over payouts, or an emitted event consumed by light clients is.

Tag: `[COS-NONDET:{source}:{file}:{line}→{state-effect}]`

2. Unmetered BeginBlock / EndBlock Hooks

**Check**: ABCI hooks (`BeginBlock`, `EndBlock`, `BeginBlocker`, `EndBlocker`, `PreBlocker`) run every block with no per-message gas meter bounding them. An unbounded or super-linear loop over state that an attacker can grow turns block production into a DoS / liveness failure.

**Methodology**: 1. Locate every `BeginBlock(er)` / `EndBlock(er)` / `PreBlocker` (grep `func.*BeginBlock`, `func.*EndBlock`, `module.go`, `abci.go`). 2. Inside each, walk loops. Flag:

  • Iteration over a `GetAll*` / `IterateAll*` / full-store iterator whose element count grows with user actions (e.g. all unbonding entries, all open orders, all proposals, all accounts) with no cap per block.
  • Nested loops over growing state (O(n²)) — e.g. for each validator, for each delegation.
  • `len(slice)` / iterator length driven by attacker-controlled creation (an attacker spams cheap objects; the hook then iterates all of them every block).

3. Confirm the absence of a per-block work cap (a `maxPerBlock` limit, a paginated queue drained N-at-a-time, or a time-bounded window). Absence with attacker-growable input is the finding.

Tag: `[COS-ABCI-UNMETERED:{hook}:{file}:{line}:{growth-driver}]`

3. GetSigners vs State-Modifying Field Mismatch

**Check**: A `Msg` may only mutate state owned by an account that is in its authenticated signer set. If a handler writes a field (owner, recipient, admin, target address) that is NOT derived from `msg.GetSigners()` (or the SDK-validated signer), an attacker can act on behalf of, or against, another account.

**Methodology**: 1. For each proto `Msg` type, find its `GetSigners()` (generated or hand-written) and record the signer-deriving field(s) (commonly `Creator`, `Sender`, `FromAddress`, `Authority`). 2. From `state_write_map.md`, list every field the corresponding `msgServer` handler writes or whose owner it changes. 3. Cross-check: every account/address the handler treats as authorized MUST be in the signer set. Flag when:

  • The handler
Read more
Ships withplamen

Autonomous Web3 security auditor for Claude Code and OpenAI Codex CLI. Orchestrates 18-100 AI agents across 40+ phases to produce audit reports with verified PoC exploits — for smart contracts and L1 node-client infrastructure.

Get the whole plugin