/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.
$ npx -y skills add PlamenTSV/plamen --skill cosmos-sdk-module-safety --agent claude-codeHow 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.mdname: "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
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
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.
Repo: PlamenTSV/plamen
Other skills on plamen.
- /ability-analysis
Trigger Pattern Always (Aptos Move) - foundational security check - Inject Into Breadth agents, depth agents
Open skill - /bit-shift-safety
Trigger Pattern Always (Aptos Move) - Move VM aborts on shift = bit width - Inject Into Breadth agents, depth-edge-case
Open skill - /centralization-risk
Trigger Protocol has privileged roles (admin, operator, governance, resource account owner) - Covers Single points of failure, privilege escalation, external governance dependen...
Open skill - /cross-chain-timing
Trigger Pattern wormhole|layerzero|ccip|bridge|cross_chain|vaa|guardian|emitter|relay|remote_chain|payload|nonce.sequence - Inject Into Breadth agents, depth-external
Open skill - /dependency-audit
Trigger EXTERNAL_LIB flag detected (protocol uses third-party Move dependencies) - Used by Breadth agents, depth-external
Open skill - /economic-design-audit
Trigger Pattern MONETARY_PARAMETER flag (required) - Inject Into Breadth agents (merged via M4 hierarchy)
Open skill

