Skip to content

WIP: Ledger security release docs (2026.1)#329

Open
evanorti wants to merge 37 commits into
mainfrom
security-release
Open

WIP: Ledger security release docs (2026.1)#329
evanorti wants to merge 37 commits into
mainfrom
security-release

Conversation

@evanorti

@evanorti evanorti commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

WIP: Ledger security release docs (2026.1)

Documentation for the 2026.1 security release: post-quantum keys (ML-DSA),
zero-downtime consensus key rotation, and remote signing via Cosmos-KMS.
Every technical claim is code- or test-verified before its page merges.

Nav: three groups under Run a Node (SDK next): Key Rotation, Post-quantum Keys,
Remote Signing: Cosmos-KMS.

Key Rotation

Post-quantum Keys

  • Post-quantum keys — keys and algorithms survey, ML-DSA, costs, EVM note
  • Enable ML-DSA keys — genesis and governance paths; governance flow test-verified
  • Migrate a validator to ML-DSA — keygen step blocked on tooling (TODO(ERIC) in page)
  • Create an ML-DSA account — test-verified on a localnet

Remote Signing: Cosmos-KMS

  • Cosmos-KMS and remote signing (overview)
  • Remote signing tutorial — test-verified e2e
  • Configure a signing backend (AWS KMS, PKCS#11, file) — AWS/PKCS#11 sections pending execution
  • Rotate a consensus key held in Cosmos-KMS — test-verified e2e
  • Cosmos-KMS configuration reference
  • Remote signing best practices
  • Migrate from TMKMS — skeleton; TODO(ERIC) sections pending content

Module references and release-impact fixes

  • x/staking README: MsgRotateConsPubKey, KeyRotationFee, rotation stores, End-Block
  • PoA api/governance/overview: RotateConsPubKey (provisional until #26590 merges)
  • run-production: TMKMS walkthrough replaced with Cosmos-KMS links + deprecation note
  • keyring: key algorithms corrected (secp256k1 + ml_dsa_65 via --key-type), new pages linked
  • run-node: state-sync-adjacent next steps, link fixes

Upgrading

  • 0.53/0.54 → 0.55 upgrade docs — blocked on UPGRADING content (FOU-754)

Verification

Five flows run end to end against local chains, commands exactly as published:
governance param change, staking rotation, ML-DSA account, kms file-backend
tutorial, and kms rotation. Each tested page carries a hidden verification
comment with environment and commits.

  • npx mint broken-links clean

Review

  • Per-page review issues with instructions live in Linear (Ledger Security Docs
    project, FOU-739 to FOU-755): rotation set → Matt, ML-DSA + kms sets → Eric,
    release notes → Alex. Open eng questions are tracked there, and as TODO(ERIC)/
    TODO(MATT) comments in the pages.

@evanorti
evanorti marked this pull request as draft July 10, 2026 19:42
@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the 2026.1 security release documentation: consensus key rotation (staking and PoA), post-quantum ML-DSA keys, and remote signing via Cosmos-KMS. The content is thorough and most guides are end-to-end verified against local chains.

  • Thirteen new pages across sdk/next/keys/ and sdk/next/kms/ cover key rotation concepts and procedures, ML-DSA key enablement and migration, and the full Cosmos-KMS lifecycle (tutorial, backend configuration, rotation, TMKMS migration, best practices, and reference).
  • Existing pages (run-production.mdx, keyring.mdx, run-node.mdx, and the staking module README) are updated to reference the new content and remove the outdated TMKMS walkthrough.
  • The algorithm/backend support matrix is stated differently in configure-backend.mdx and configuration-reference.mdx: the reference says mldsa65 is file-only while configure-backend and the work log confirm it works on all three backends; the reference says secp256k1eth is file-only while configure-backend lists it under AWS KMS — these two pages need to be reconciled before the content ships.

Confidence Score: 4/5

Safe to merge after reconciling the algorithm/backend matrix between configuration-reference.mdx and configure-backend.mdx; all other content is well-verified.

The two KMS pages disagree about which algorithms each backend supports: the reference says mldsa65 is file-only while the configure-backend page and the work log confirm it works on all three backends; the configure-backend page says AWS KMS supports secp256k1eth while the reference (backed by source traces in the work log) says secp256k1eth is file-only. An operator configuring a production mldsa65 setup against AWS KMS would get the wrong answer from whichever page they consult. Everything else in the PR is consistent and well-grounded.

sdk/next/kms/configuration-reference.mdx and sdk/next/kms/configure-backend.mdx need to be reconciled on the per-backend algorithm support matrix before this ships.

Important Files Changed

Filename Overview
sdk/next/kms/configuration-reference.mdx New reference page for kms.yaml fields; line 44's algorithm/backend matrix incorrectly restricts mldsa65 to the file backend, contradicting configure-backend.mdx and the work-log's source confirmation that mldsa65 works on all three backends.
sdk/next/kms/configure-backend.mdx New guide for AWS KMS, PKCS#11, and file backends; line 20 overstates AWS KMS algorithm coverage by including secp256k1eth, which contradicts the configuration-reference and work-log source trace identifying secp256k1eth as file-only.
sdk/next/kms/tutorial-file-backend.mdx New end-to-end tutorial for Cosmos-KMS file backend; startup timing race condition between signer and node is clearly documented in a Note callout; no issues found.
sdk/next/kms/rotate-key-remote-signer.mdx New tutorial for rotating a consensus key held in Cosmos-KMS; procedure is well-grounded with a hidden e2e verification comment; double-sign danger is clearly called out.
sdk/next/kms/migrate-from-tmkms.mdx New migration guide from TMKMS to Cosmos-KMS; tmkms.toml-to-kms.yaml mapping table is thorough; softsign key conversion is verified; double-sign cutover procedure has a clear Danger callout.
sdk/next/kms/best-practices.mdx New best practices page for remote signing; covers placement, transport pinning, key protection levels, and the one-signer rule; no issues found.
sdk/next/keys/key-rotation.mdx New concept page for consensus key rotation; covers mechanics, safety rails, PoA differences, and slashing accountability; no new issues beyond those already in review threads.
sdk/next/keys/rotate-validator-key.mdx New zero-downtime staking rotation tutorial; localnet-verified; double-sign danger and rotation limit edge cases are clearly documented.
sdk/next/keys/post-quantum-keys.mdx New survey of key types and ML-DSA; cost table is accurate; EVM post-quantum path correctly tied to EIP-7702/8051/8141 roadmap; no issues found.
sdk/next/modules/staking/README.mdx Adds MsgRotateConsPubKey message docs, KeyRotationFee parameter row, four rotation state stores, and end-block lifecycle; links back to the procedural guides; no issues found.
sdk/next/node/run-production.mdx Replaces the full TMKMS walkthrough with a brief Cosmos-KMS pointer and a migration note; no issues found.
work-log/security-release.md Work log for the security release branch; entries are out of chronological order and are far more verbose than the short guideline in work-log/CLAUDE.md.
docs.json Adds three nav groups (Key Rotation, Post-quantum Keys, Remote Signing: Cosmos-KMS) under Run a Node; all new pages are registered; structure uses a Guides subgroup correctly.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Op as Operator
    participant Node as Validator Node
    participant KMS as Cosmos-KMS
    participant Backend as Key Backend
    participant Chain as Chain

    Note over Op,Chain: Setup
    Op->>KMS: kms init --home ~/.kms
    Op->>KMS: Configure kms.yaml
    Op->>Node: Set priv_validator_laddr

    Note over Op,Chain: Startup
    Op->>KMS: kms start
    KMS->>Node: dial tcp://host:26659 (retries)
    Op->>Node: simd start
    Node-->>KMS: privval connection accepted
    KMS->>Backend: load / fetch key
    Backend-->>KMS: key material
    Node->>KMS: GetPubKey request
    KMS-->>Node: consensus public key

    Note over Op,Chain: Per-block signing
    Node->>KMS: SignVote / SignProposal
    KMS->>Backend: sign(message)
    Backend-->>KMS: signature
    KMS-->>Node: signed vote / proposal
    Node->>Chain: broadcast signed vote

    Note over Op,Chain: Key rotation
    Op->>KMS: kms init --home ~/.kms2
    Op->>Node: simd start shadow node
    Op->>Chain: MsgRotateConsPubKey
    Chain-->>Node: validator set update
    Op->>KMS: stop old signer and node
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Op as Operator
    participant Node as Validator Node
    participant KMS as Cosmos-KMS
    participant Backend as Key Backend
    participant Chain as Chain

    Note over Op,Chain: Setup
    Op->>KMS: kms init --home ~/.kms
    Op->>KMS: Configure kms.yaml
    Op->>Node: Set priv_validator_laddr

    Note over Op,Chain: Startup
    Op->>KMS: kms start
    KMS->>Node: dial tcp://host:26659 (retries)
    Op->>Node: simd start
    Node-->>KMS: privval connection accepted
    KMS->>Backend: load / fetch key
    Backend-->>KMS: key material
    Node->>KMS: GetPubKey request
    KMS-->>Node: consensus public key

    Note over Op,Chain: Per-block signing
    Node->>KMS: SignVote / SignProposal
    KMS->>Backend: sign(message)
    Backend-->>KMS: signature
    KMS-->>Node: signed vote / proposal
    Node->>Chain: broadcast signed vote

    Note over Op,Chain: Key rotation
    Op->>KMS: kms init --home ~/.kms2
    Op->>Node: simd start shadow node
    Op->>Chain: MsgRotateConsPubKey
    Chain-->>Node: validator set update
    Op->>KMS: stop old signer and node
Loading

Reviews (3): Last reviewed commit: "Update tutorial-file-backend.mdx" | Re-trigger Greptile

Comment thread sdk/next/keys/key-rotation.mdx
@mintlify

mintlify Bot commented Jul 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
cosmos-docs 🟢 Ready View Preview Jul 10, 2026, 7:56 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

docs(sdk): kms rotation guide, release-impact fixes, prerequisites pass

Add rotate-key-remote-signer: rotate a consensus key held in Cosmos-KMS
(second signer process, shadow node, pubkey from /status). Test-verified
e2e on a localnet; includes the show-validator stray-key trap as a Danger.

Release-impact fixes to existing pages:
- run-production: replace the deprecated TMKMS walkthrough with
  Cosmos-KMS links and a deprecation note
- keyring: correct key algorithms to secp256k1 + ml_dsa_65 via
  --key-type (was ed25519 via --algo), link the new keys pages,
  fix a broken in-page anchor
- run-node: next-step links to key rotation and remote signing;
  jq links moved to jqlang.org

Guide improvements:
- complete, linked prerequisites on every keys/ and kms/ guide
- migrate-validator-ml-dsa: step 2 split into labeled staking / PoA /
  remote signer paths with the exact deltas (PoA passes ml_dsa_65)
- state-sync pointers on both shadow-node rotation pages
- post-quantum-keys: EIP-7702/8051/8141 linked and corrected
- Cosmos-KMS naming in prose, bare "kms" replaced with "the signer"
- remote-signing next steps completed (resolves placeholder TODO)
@evanorti

Copy link
Copy Markdown
Contributor Author

@greptileai plz rereview

Comment thread sdk/next/keys/post-quantum-keys.mdx Outdated
Comment thread sdk/next/keys/rotate-validator-key-poa.mdx Outdated
Comment thread sdk/next/keys/migrate-validator-ml-dsa.mdx Outdated
Comment thread sdk/next/keys/rotate-validator-key.mdx Outdated
Comment thread sdk/next/keys/rotate-validator-key-poa.mdx
Comment thread sdk/next/kms/remote-signing.mdx
Comment thread sdk/next/kms/remote-signing.mdx Outdated
Comment thread sdk/next/kms/tutorial-file-backend.mdx Outdated
Comment thread sdk/next/kms/best-practices.mdx
Comment thread sdk/next/kms/best-practices.mdx
Comment thread sdk/next/kms/configure-backend.mdx
Comment thread sdk/next/keys/key-rotation.mdx Outdated
2. A validator can rotate once per unbonding period. Until the unbonding period ends, the previous key remains accountable, so the chain rejects a second rotation inside the window.
3. A rotation cannot be undone. No cancel message exists, and the once-per-unbonding-period limit blocks an immediate rotation back, so an applied rotation stands until the window expires.

Slashing follows a validator's history, not the key. The chain keeps a mapping from each historical consensus address to its validator for the length of the unbonding period, so evidence of a double sign under the old key still slashes the validator after rotation. Rotating away from a key does not allow a validator to escape slashing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chain keeps a mapping from each historical consensus address to its validator for the length of the unbonding period

This has changed slightly and is no longer correct. When the rotation message lands on chain, we take a snapshot of the consensus params and specifically the evidence MaxAgeNumBlocks and MaxAgeDuration that dictate how long evidence is valid for after it is observed. After both MaxAgeNumBlocks and MaxAgeDuration have elapsed, we stop tracking this historical consensus address. This may be months depending on what the chain has these values configured as.

This has an interesting trade off however that is very important to document (we may want like a things to know section or security implications or something like that). This snapshot of the values is never modified from the values that it computes at rotation time. So for example: If a rotation is submitted and based on MaxAgeNumBlocks and MaxAgeDuration, the rotation history will be kept for 500 blocks. That 500 blocks value will never change, even if MaxAgeNumBlocks or MaxAgeDuration are extended by a gov prop. So if the computed value would have now been 600 blocks, we do not make any updates to the rotation in state to reflect this, and at 500 blocks past the rotation, the history of the rotation will go away and there will be a period where evidence can be submitted against a validators previous consensus address and it is not able to be slashed, effectively evading double slashing. This is an accepted risk and chains should not extend these values while rotations are in flight without understanding these consequences.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added here:

## Safety rails
Three rules bound what a rotation can do:
1. A rotation burns a flat fee, set by the `KeyRotationFee` staking param, to make rotation spam expensive.
2. A validator can rotate once per unbonding period. Until the unbonding period ends, the previous key remains accountable, so the chain rejects a second rotation inside the window.
3. A rotation cannot be undone. No cancel message exists, and the once-per-unbonding-period limit blocks an immediate rotation back, so an applied rotation stands until the window expires.
## Security implications
<Danger>Read this section carefully. Key rotation introduces security and performance tradeoffs that chains must be aware of before rotating keys.</Danger>
### Slashing window length
Slashing follows a validator's history, not the key. Evidence of a double sign under the old key still slashes the validator after rotation. When a rotation lands, the chain records the old consensus address. It keeps that address tied to the validator. It tracks the address for as long as evidence against it can still be admitted. It computes this window at rotation time from the evidence params `MaxAgeNumBlocks` and `MaxAgeDuration`. Once both elapse, the chain stops tracking the address. The window can be months, depending on the chain's evidence settings. Rotating away from a key does not let a validator escape slashing within that window.
The chain computes a rotation tracking window once at the time of rotation. It never updates this window. If governance extends `MaxAgeNumBlocks` or `MaxAgeDuration` after a rotation, the original window for the rotation remains in effect. In this scenario, the old consensus address will stop being tracked before the current evidence window closes. During that gap, a double sign under the old key cannot be slashed. This is a risk that chains should be aware of. Do not extend the evidence params while rotations are in flight without accounting for it.
### Increased light client verification cost
Frequent rotations also raise the cost of light client updates. Each rotation changes the validator set. Tendermint light clients verify an update using the overlap between successive validator sets. Heavy rotation churn shrinks that overlap, and less overlap makes each update more expensive to verify. The once-per-unbonding-period limit exists partly to bound this cost.
### Proposer priority reset
Rotation resets the validator's proposer priority. CometBFT orders validators by a proposer priority value. That value decides when a validator's turn to propose comes up. A rotation sends the validator to the back of that order. This holds even if the validator was next in line to propose.
### Mixed key types slow down
A validator set with mixed consensus key types verifies signatures more slowly. CometBFT batch-verifies signatures when every validator uses the same key type. Batch verification is faster than checking each signature on its own. One validator on a different key type breaks batching. Verification then falls back to one signature at a time, which can slow block times. This applies whenever the set holds more than one key type, not only during a rotation.

Comment thread sdk/next/modules/staking/README.mdx Outdated
Comment thread sdk/next/keys/key-rotation.mdx Outdated
Comment thread sdk/next/keys/key-rotation.mdx Outdated
Comment thread sdk/next/keys/key-rotation.mdx Outdated
Comment thread sdk/next/kms/best-practices.mdx
Comment thread sdk/next/kms/remote-signing.mdx
Comment thread sdk/next/kms/remote-signing.mdx
* update Cometbft and SDK docs for v0.55 and v0.40 release

* Update block-sync.mdx

* Update configuration.mdx
Comment thread sdk/next/kms/configure-backend.mdx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants