All skills
Skillintermediate

ADVANCED VULNERABILITY PATTERNS

> Updated for Cosmos SDK v0.53.x. Advanced infrastructure patterns (§24-27) covering storage key design, consensus validation gaps, circuit breaker authorization, and cryptographic verification. Referenced by [SKILL.md](../SKILL.md) checklist items via `§` anchors.

Claude Code Knowledge Pack7/10/2026

Overview

Advanced Vulnerability Patterns

Updated for Cosmos SDK v0.53.x. Advanced infrastructure patterns (§24-27) covering storage key design, consensus validation gaps, circuit breaker authorization, and cryptographic verification. Referenced by SKILL.md checklist items via § anchors.

24 STORAGE KEY DESIGN FLAWS

Description: KV store key construction allows collisions, prefix overlaps, or unauthorized access to other users' data. Keys built via string concatenation without length-prefixed encoding create ambiguous boundaries. Numeric fields serialized as variable-length strings share byte prefixes. Prefix iterators over attacker-controllable components include unintended objects.

Detection Patterns:

Pattern 1: String Concatenation Collision

// VULNERABLE: String concatenation without length-prefix encoding (Finding 16)
func VaultUserKey(vaultID uint64, user string) []byte {
    return []byte(fmt.Sprintf("%d%s", vaultID, user))
}
// vaultId=1, user="2a" → key "12a"
// vaultId=12, user="a" → key "12a"  ← COLLISION!

// Even with separators, string fields containing the separator collide:
// vaultId=1, user="a|", position="b" → "1|a||b"
// vaultId=1, user="a", position="|b" → "1|a||b"  ← COLLISION!

Pattern 2: Prefix Iterator Malleability

// VULNERABLE: Pool IDs serialized as strings in KV store keys (Finding 31)
func PositionKey(poolID uint64, posID uint64) []byte {
    return []byte(fmt.Sprintf("position/%d/%d", poolID, posID))
}
// poolID=42 shares byte prefix [52 50] with poolID=421
// HasAnyAtPrefix("position/42") matches "position/421/..."
// Attacker creates positions with carefully chosen pool IDs
// that prefix-collide with victim positions

// VULNERABLE: Attacker can increment pool IDs by creating empty pools
store.Iterator(PositionPrefix(poolID), nil)  // Includes poolID * 10 + N

Pattern 3: Redelegation State Lookup Bypass

// VULNERABLE: Unbonding period bypass via redelegation (Finding 14)
// If a user redelegates to a validator outside the active set
// (e.g., bonded stake rank 102), then unbonds, the 21-day
// unbonding period is skipped — the state key lookup for the
// unbonding entry doesn't account for out-of-set validators.
// Attacker who steals tokens can instantly exit staking.

What to Check:

  • KV store keys use length-prefixed encoding (e.g., collections.PairKeyCodec, address.LengthPrefixedAddressKey) — NOT string concatenation
  • Prefix iterators cannot be confused by attacker-controllable numeric IDs (e.g., pool IDs serialized as fixed-width or length-prefixed)
  • String fields in composite keys cannot contain the separator character
  • HasAnyAtPrefix / Iterator with user-influenced prefix components verified to not match unintended keys
  • Redelegation to out-of-set validators followed by unbonding is tested against unbonding period enforcement

Mitigation:

// SECURE: Use length-prefixed encoding
func VaultUserKey(vaultID uint64, user string) []byte {
    key := make([]byte, 8+1+len(user))
    binary.BigEndian.PutUint64(key[:8], vaultID)  // Fixed-width
    key[8] = byte(len(user))                       // Length prefix
    copy(key[9:], user)
    return key
}

// SECURE: Use cosmossdk.io/collections key codecs
var PositionsMap = collections.NewMap(
    sb, PositionsPrefix,
    collections.PairKeyCodec(collections.Uint64Key, collections.Uint64Key),
    codec.CollValue[Position](cdc),
)

References:


25 CONSENSUS VALIDATION GAPS

Description: Missing or incomplete validation at the consensus protocol layer — vote extensions, block timestamp manipulation, and account type checks at creation time. These allow Byzantine validators or front-running attackers to manipulate consensus-level data that downstream modules trust implicitly.

Detection Patterns:

Pattern 1: Vote Extension Forgery

// VULNERABLE: PrepareProposal validates signatures but skips
// VerifyVoteExtension rules (Finding 15, SEDA Chain)
func (h *Handler) PrepareProposal(ctx sdk.Context, req *abci.PrepareProposalRequest) (*abci.PrepareProposalResponse, error) {
    for _, vote := range req.LocalLastCommit.Votes {
        // Only checks vote signature — does NOT re-run VerifyVoteExtension!
        if !verifySignature(vote) { continue }
        // CometBFT accepts late precommits without full verification
        // Byzantine validator smuggles malicious vote extension into proposal
        extensions = append(extensions, vote.VoteExtension)
    }
    // Leader unknowingly includes forged oracle data in block
}

Pattern 2: Block Timestamp Manipulation

// VULNERABLE: Any module trusting ctx.BlockTime() for security-critical decisions
// CometBFT "Tachyon" (Finding 21, CSA-2026-001): inconsistency between how
// commit signatures are verified and how block time is derived breaks BFT Time
// guarantee. A faulty process CAN arbitrarily increase block time.

// These are all exploitable if block time can be manipulated:
deadline := proposal.SubmitTime.Add(votingPeriod)
if ctx.BlockTime().After(deadline) { ... }  // Governance deadlines

vestingEnd := account.EndTime
if ctx.BlockTime().After(vestingEnd) { ... }  // Vesting unlocks

price := oracle.GetTWAP(ctx, pair, window)  // Time-weighted prices

Pattern 3: Vesting on Blocked/Module Addresses

// VULNERABLE: Creating vesting accounts on blocked addresses (Finding 29, ASA-2024-003)
func (ms msgServer) CreatePeriodicVestingAccount(ctx context.Context, msg *types.MsgCreatePeriodicVestingAccount) error {
    toAddr := sdk.AccAddressFromBech32(msg.ToAddress)
    // Missing: check if toAddress is a blocked address or module account
    // Funds deposited to module accounts via vesting become permanently inaccessible
    // Could also enable unintended interactions with module accounts
}

What to Check:

  • PrepareProposal re-validates vote extensions using the same rules as VerifyVoteExtension — do NOT trust that CometBFT has already validated them (late precommits may skip verification)
  • ProcessProposal independently validates all vote extensions included in the proposal
  • Vote extension content is treated as untrusted input even from non-Byzantine validators
  • CometBFT is patched for Tachyon (>= v0.38.21 / v0.37.18) — block timestamp manipulation
  • Time-dependent logic (governance deadlines, vesting unlocks, oracle TWAPs, lockup periods, auction timers) is reviewed against block time manipulation
  • CreateVestingAccount / CreatePeriodicVestingAccount reject blocked addresses and non-initialized module accounts as recipients
  • SDK version includes Barberry patches (>= v0.46.13, >= v0.47.3) for vesting on blocked addresses

References:


26 CIRCUIT BREAKER AUTHZ BYPASS

Description: The x/circuit module allows authorized accounts to disable (circuit-break) specific message types during incident response. An authorization scope bug allows an account authorized to circuit-break specific message types to reset the circuit breaker for any message type, even those it lacks permission for. This can re-enable message types intentionally disabled for security.

Detection Patterns:

// VULNERABLE: Circuit breaker reset does not verify per-type authorization
// Account authorized to break MsgSend can reset MsgDelegate
func (ms msgServer) ResetCircuitBreaker(ctx context.Context, msg *types.MsgResetCircuitBreaker) error {
    // Checks: is the sender an authorized circuit breaker account? YES
    // Missing: does the sender have authority over THIS SPECIFIC message type?
    // Result: any circuit breaker account can re-enable any disabled message type
}

What to Check:

  • x/circuit reset/authorize operations validate per-message-type permissions (not just "is this a circuit breaker account")
  • Circuit breaker accounts have minimal scope — only the message types they are responsible for
  • Re-enabling a circuit-broken message type requires the same or higher authorization level as disabling it
  • During incident response, monitor for unexpected circuit breaker resets

Grep Patterns (use Grep tool):

  • circuit|CircuitBreaker|ResetCircuitBreaker with glob: "*.go" in x/
  • x/circuit with glob: "*.go" in app/

References:


27 MERKLE PROOF / CRYPTOGRAPHIC VERIFICATION FLAWS

Description: Specification-level or implementation-level flaws in cryptographic proof systems allow forging proofs that should be computationally infeasible. ICS-23 was unsound at the spec level (not just implementation). Cross-chain bridges that verify proofs differently on each side create asymmetric validation. This class has caused the largest single loss in the Cosmos ecosystem ($566M BNB bridge exploit, related flaw).

Detection Patterns:

Pattern 1: ICS-23 Absence Proof Forgery

// VULNERABLE: ICS-23 spec allowed proofs to carry their own spec parameters
// (Finding 3a, Dragonberry — all IBC chains, all versions)
// Validation only required input leaf prefix to CONTAIN the standard spec's
// prefix as a substring — not match exactly.
// Attacker forges absence proof to "prove" packet commitment doesn't exist
// on counterparty chain (even though it does), then triggers IBC timeout refunds
// for packets that were successfully delivered.
// Iterative drainage of ALL ICS-20 escrow accounts across ALL Cosmos networks.

Pattern 2: IAVL RangeProof Forgery

// VULNERABLE: Same class as Dragonberry in IAVL RangeProof system
// (Finding 30, Dragonfruit — $566M BNB bridge exploit used related flaw)
// Missing validation checks on leaf/inner-node prefix/suffix length
// allowed forging proofs against the IAVL Merkle tree.

Pattern 3: ECDSA Signature Malleability

// VULNERABLE: Cosmos-side ECDSA verification accepts non-canonical s-values
// (Finding 13, Gravity Bridge)
func EthAddressFromSignature(hash []byte, sig []byte) (common.Address, error) {
    // Missing: canonical s-value validation
    // ECDSA has two valid s values per signature (elliptic curve symmetry)
    // Ethereum enforces s < secp256k1.N/2, Cosmos side does not
    // Malicious orchestrator submits non-canonical signature:
    //   Cosmos accepts → Ethereum rejects → bridge enters crash loop
    //   Selectively block validator set updates and transaction batches
}

What to Check:

  • ICS-23 proof verification uses patched libraries — leaf prefix must match exactly, not just contain as substring
  • IAVL library patched for Dragonfruit (prefix/suffix length validation on inner/leaf nodes)
  • ECDSA signature verification enforces canonical s-value (s < secp256k1.N/2) on BOTH sides of any bridge
  • Cross-chain proof verification is symmetric — same validation on source and destination
  • Custom Merkle proof implementations do not allow proof parameters to be attacker-controlled
  • If using BLS, ed25519, or other signature schemes for cross-chain verification, signature malleability is addressed

Grep Patterns (use Grep tool with glob: "*.go" in x/):

  • VerifyMembership|VerifyNonMembership|VerifyProof — proof verification
  • RangeProof|InnerNode|LeafNode — Merkle tree operations
  • EthAddressFromSignature|RecoverPubkey|Ecrecover — signature recovery

References: