Security: no emergency governance key rotation rehearsal or named signer list in runbooks [SEC-D10] #408

Closed
opened 2026-06-19 11:45:35 +00:00 by totdking · 15 comments
totdking commented 2026-06-19 11:45:35 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-19 11:46:29 +00:00 (Migrated from gitlab.com)

Checklist Item

SEC-D10: Model admin-key compromise as the most realistic high-impact attack for small TVL. Verify: governance custody/runbook review and emergency rotation rehearsal.


Summary

The security model documents that governance should be a multisig and the launch checklist requires multisig governance as a Phase 0 gate. However, no runbook includes an emergency key rotation script, a named signer list, a rotation ceremony procedure, or evidence that an emergency rotation has been rehearsed. The issue DEX-P2-026 ("Runbook: contract migration / admin key rotation") remains in the issue backlog as unimplemented.


What Was Checked

  • docs/runbooks/wasm-admin-migration.md "Admin rotation" section: one-liner -- "Use update_admin (where supported) only through governance process; verify new admin on-chain before revoking old keys"; no named signers, no rotation script, no rehearsal record
  • docs/runbooks/launch-checklist.md Phase 0: requires "Governance and treasury addresses are multisigs or DAO (not EOAs)"; requirement noted but no rotation rehearsal step
  • docs/security-model.md Governance Keys: states governance address should be multisig; policy stated, no rehearsal documented
  • docs/reviews/20260409T030009Z/ISSUE_BACKLOG.md line 246: "DEX-P2-026 -- Runbook: contract migration / admin key rotation"; backlog only, not implemented
  • Entire docs/ tree searched for "emergency rotation", "rotation rehearsal", "signer list", "key rotation": no results outside the above

Expected (per checklist)

A documented governance custody plan and evidence of an emergency rotation rehearsal. This includes: named signers or multisig threshold, a copy-pastable rotation command sequence, and a record that the rotation was tested on LocalTerra or staging.


Actual

The runbook has a policy statement (multisig required) and a one-line reminder to use update_admin through governance, but no named signer list, no rotation command cookbook, and no rehearsal record. Admin key compromise is identified in SEC-D as the most realistic high-impact attack at small TVL, yet the rotation procedure is the least-documented emergency action in the repo.


Evidence

  • docs/runbooks/wasm-admin-migration.md lines 38-40: "Admin rotation" section is one bullet only
  • docs/reviews/20260409T030009Z/ISSUE_BACKLOG.md line 246: DEX-P2-026 in backlog, not implemented
  • No rotation script found in docs/, scripts/, or Makefile

Suggested Fix

Implement DEX-P2-026. Add a section to docs/runbooks/wasm-admin-migration.md (or a new docs/runbooks/governance-key-rotation.md) that includes:

  1. Named signers and multisig threshold (or a pointer to where this is documented privately)
  2. Copy-pastable terrad tx wasm update-admin command with placeholder addresses
  3. Copy-pastable terrad tx wasm execute command for factory UpdateConfig { governance: new_addr } rotation
  4. Post-rotation verification queries
  5. A record that this sequence was rehearsed on LocalTerra or testnet with a timestamp and the rehearsing developer's name

Verification Checklist

  • docs/runbooks/wasm-admin-migration.md or a dedicated rotation runbook contains copy-pastable rotation commands
  • Runbook identifies the multisig threshold and expected signers (or references where this is stored)
  • A rehearsal record or LocalTerra transcript is attached to the launch tracking issue or linked from the runbook
  • DEX-P2-026 is closed with a link to the completed runbook

Labels

security, pre-launch

Cc: @PlasticDigits

### Checklist Item SEC-D10: Model admin-key compromise as the most realistic high-impact attack for small TVL. Verify: governance custody/runbook review and emergency rotation rehearsal. --- ### Summary The security model documents that governance should be a multisig and the launch checklist requires multisig governance as a Phase 0 gate. However, no runbook includes an emergency key rotation script, a named signer list, a rotation ceremony procedure, or evidence that an emergency rotation has been rehearsed. The issue DEX-P2-026 ("Runbook: contract migration / admin key rotation") remains in the issue backlog as unimplemented. --- ### What Was Checked - `docs/runbooks/wasm-admin-migration.md` "Admin rotation" section: one-liner -- "Use update_admin (where supported) only through governance process; verify new admin on-chain before revoking old keys"; no named signers, no rotation script, no rehearsal record - `docs/runbooks/launch-checklist.md` Phase 0: requires "Governance and treasury addresses are multisigs or DAO (not EOAs)"; requirement noted but no rotation rehearsal step - `docs/security-model.md` Governance Keys: states governance address should be multisig; policy stated, no rehearsal documented - `docs/reviews/20260409T030009Z/ISSUE_BACKLOG.md` line 246: "DEX-P2-026 -- Runbook: contract migration / admin key rotation"; backlog only, not implemented - Entire `docs/` tree searched for "emergency rotation", "rotation rehearsal", "signer list", "key rotation": no results outside the above --- ### Expected (per checklist) A documented governance custody plan and evidence of an emergency rotation rehearsal. This includes: named signers or multisig threshold, a copy-pastable rotation command sequence, and a record that the rotation was tested on LocalTerra or staging. --- ### Actual The runbook has a policy statement (multisig required) and a one-line reminder to use `update_admin` through governance, but no named signer list, no rotation command cookbook, and no rehearsal record. Admin key compromise is identified in SEC-D as the most realistic high-impact attack at small TVL, yet the rotation procedure is the least-documented emergency action in the repo. --- ### Evidence - `docs/runbooks/wasm-admin-migration.md` lines 38-40: "Admin rotation" section is one bullet only - `docs/reviews/20260409T030009Z/ISSUE_BACKLOG.md` line 246: DEX-P2-026 in backlog, not implemented - No rotation script found in `docs/`, `scripts/`, or `Makefile` --- ### Suggested Fix Implement DEX-P2-026. Add a section to `docs/runbooks/wasm-admin-migration.md` (or a new `docs/runbooks/governance-key-rotation.md`) that includes: 1. Named signers and multisig threshold (or a pointer to where this is documented privately) 2. Copy-pastable `terrad tx wasm update-admin` command with placeholder addresses 3. Copy-pastable `terrad tx wasm execute` command for factory `UpdateConfig { governance: new_addr }` rotation 4. Post-rotation verification queries 5. A record that this sequence was rehearsed on LocalTerra or testnet with a timestamp and the rehearsing developer's name --- ### Verification Checklist - [ ] `docs/runbooks/wasm-admin-migration.md` or a dedicated rotation runbook contains copy-pastable rotation commands - [ ] Runbook identifies the multisig threshold and expected signers (or references where this is stored) - [ ] A rehearsal record or LocalTerra transcript is attached to the launch tracking issue or linked from the runbook - [ ] DEX-P2-026 is closed with a link to the completed runbook --- ### Labels `security`, `pre-launch` Cc: @PlasticDigits
totdking commented 2026-06-19 12:06:49 +00:00 (Migrated from gitlab.com)

mentioned in issue #381

mentioned in issue #381
PlasticDigits commented 2026-06-19 13:13:01 +00:00 (Migrated from gitlab.com)

Pending multisig release.

Pending multisig release.
PlasticDigits commented 2026-06-19 13:24:04 +00:00 (Migrated from gitlab.com)

mentioned in merge request !935

mentioned in merge request !935
PlasticDigits commented 2026-06-25 11:37:43 +00:00 (Migrated from gitlab.com)

mentioned in issue #406

mentioned in issue #406
PlasticDigits commented 2026-06-29 00:21:33 +00:00 (Migrated from gitlab.com)

mentioned in issue #424

mentioned in issue #424
Brouie commented 2026-06-30 13:48:27 +00:00 (Migrated from gitlab.com)

mentioned in commit f1091f011f

mentioned in commit f1091f011f218eefbf642c792db723b33400e180
Brouie commented 2026-06-30 13:48:43 +00:00 (Migrated from gitlab.com)

mentioned in merge request !978

mentioned in merge request !978
Brouie commented 2026-06-30 13:49:06 +00:00 (Migrated from gitlab.com)

mentioned in issue #398

mentioned in issue #398
Brouie commented 2026-06-30 14:24:00 +00:00 (Migrated from gitlab.com)

mentioned in commit afc5c92acb

mentioned in commit afc5c92acb89a964e6a9ca48c73540cb978f5d31
Brouie commented 2026-06-30 14:24:29 +00:00 (Migrated from gitlab.com)

mentioned in merge request !979

mentioned in merge request !979
Brouie commented 2026-06-30 14:25:07 +00:00 (Migrated from gitlab.com)

Took SEC-D10 and built the rotation cookbook + a real LocalTerra rehearsal. MR !979 (stacked on !978/#398), commit afc5c92a. Implements the backlog DEX-P2-026.

New docs/runbooks/governance-key-rotation.md covers the checklist:

  • copy-paste rotation commands for both admin keys — the wasm contract-admin (terrad tx wasm set-contract-admin) and the factory governance pointer ({"update_config":{"governance":...}}), single-key and multisig (generate-only -> sign --multisig -> multisign -> broadcast)
  • post-rotation verification queries (contract_info.admin, config.governance)
  • threshold + expected signers point at the key-custody roster (SEC-B10/#398) rather than restating them
  • clear-contract-admin flagged as irreversible

Heads up: the issue's suggested terrad tx wasm update-admin is outdated — terrad 4.0.1 uses set-contract-admin. The whole cookbook uses the correct subcommand; I caught it because I actually ran the rotation.

Rehearsal: I ran a wasm contract-admin round-trip on LocalTerra — current admin -> a throwaway 2-of-3 multisig -> back to the original, with the return rotation signed by the multisig (the real "rotate away from the old multisig" case). It verifies the admin on chain at each step and restores the original, so it doesn't disturb the deploy (it never touches the governance pointer). make verify-issue-408 -> 5/5. Rehearsal record:

Field Value
Network localterra
Contract factory terra1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3ysc6mpf5
Original admin (restored) terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v
Rehearsal multisig terra1jmmjdnp4r6e2spzuzatj7q05grr08yraq0gua6 (2-of-3)
forward set-contract-admin (key -> multisig) 5A39F4B7C8FE386741A8B018A49D88B65751F829AC379C2D3695C730B519FBFD
return set-contract-admin (multisig -> original) 301B55AB42EA197CB08A2A665F3EE625A4F217367AD1FA5AFC36A0D6252260C7

That's the dev rehearsal (proves the signing flow + message shapes). The launch gate still wants the same rotation repeated from the planned production multisig on testnet/staging once the multisig exists — which is your "pending multisig release". I left the real signer identities/addresses/threshold as ceremony placeholders, didn't invent any.

DEX-P2-026 is marked shipped in the review backlog with a link to the runbook.

Stacked on !978 — merge that first, then this. Needs your review + merge. @PlasticDigits

Took SEC-D10 and built the rotation cookbook + a real LocalTerra rehearsal. MR !979 (stacked on !978/#398), commit `afc5c92a`. Implements the backlog DEX-P2-026. New `docs/runbooks/governance-key-rotation.md` covers the checklist: - copy-paste rotation commands for both admin keys — the **wasm contract-admin** (`terrad tx wasm set-contract-admin`) and the factory **`governance` pointer** (`{"update_config":{"governance":...}}`), single-key and multisig (generate-only -> sign --multisig -> multisign -> broadcast) - post-rotation verification queries (`contract_info.admin`, `config.governance`) - threshold + expected signers point at the key-custody roster (SEC-B10/#398) rather than restating them - `clear-contract-admin` flagged as irreversible Heads up: the issue's suggested `terrad tx wasm update-admin` is outdated — terrad 4.0.1 uses **`set-contract-admin`**. The whole cookbook uses the correct subcommand; I caught it because I actually ran the rotation. Rehearsal: I ran a wasm contract-admin round-trip on LocalTerra — current admin -> a throwaway 2-of-3 multisig -> back to the original, with the **return** rotation signed by the multisig (the real "rotate away from the old multisig" case). It verifies the admin on chain at each step and restores the original, so it doesn't disturb the deploy (it never touches the `governance` pointer). `make verify-issue-408` -> 5/5. Rehearsal record: | Field | Value | |-------|-------| | Network | localterra | | Contract | factory `terra1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3ysc6mpf5` | | Original admin (restored) | `terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v` | | Rehearsal multisig | `terra1jmmjdnp4r6e2spzuzatj7q05grr08yraq0gua6` (2-of-3) | | forward set-contract-admin (key -> multisig) | `5A39F4B7C8FE386741A8B018A49D88B65751F829AC379C2D3695C730B519FBFD` | | return set-contract-admin (multisig -> original) | `301B55AB42EA197CB08A2A665F3EE625A4F217367AD1FA5AFC36A0D6252260C7` | That's the dev rehearsal (proves the signing flow + message shapes). The launch gate still wants the same rotation repeated from the planned production multisig on testnet/staging once the multisig exists — which is your "pending multisig release". I left the real signer identities/addresses/threshold as ceremony placeholders, didn't invent any. DEX-P2-026 is marked shipped in the review backlog with a link to the runbook. Stacked on !978 — merge that first, then this. Needs your review + merge. @PlasticDigits
PlasticDigits commented 2026-06-30 14:51:09 +00:00 (Migrated from gitlab.com)

mentioned in commit d5f277e85d

mentioned in commit d5f277e85ddbd63bba6d4f01becd58fa66df4dc2
PlasticDigits commented 2026-07-01 05:22:00 +00:00 (Migrated from gitlab.com)

Our multisig address is set up to : terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7

Our multisig address is set up to : terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7
PlasticDigits commented 2026-07-01 06:52:14 +00:00 (Migrated from gitlab.com)

Implementation verification (#408 / SEC-D10)

Verified on main (post-!979). No additional code/doc changes were required in this pass.

Acceptance criteria

Criterion How verified Result
Rotation runbook with copy-pastable commands docs/runbooks/governance-key-rotation.md — set-contract-admin, update_config, multisig flow, post-rotation queries PASS
Multisig threshold + signers (or private reference) Runbook §5 → docs/runbooks/key-custody.md (SEC-B10); production multisig terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7 in docs/reference/governance-multisig.md PASS
Rehearsal record / LocalTerra transcript make verify-issue-408 step [5] — live round-trip on fresh LocalTerra deploy PASS
DEX-P2-026 closed with runbook link docs/reviews/20260409T030009Z/ISSUE_BACKLOG.md — marked shipped → governance-key-rotation.md PASS

Commands run

make check-governance-key-rotation-docs   # OK
make verify-issue-408                       # PASS: 5  FAIL: 0  SKIP: 0

LocalTerra rehearsal (from make verify-issue-408):

  • Factory: terra1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3ysc6mpf5
  • Original admin (restored): terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v
  • Rehearsal multisig (2-of-3): terra1hs6jfpxltzcyask9e3zmkfugydvngh4dyer3sz
  • Forward set-contract-admin (key → multisig): E5710AFECC973F1820226DD1485145E4E8CCDC97FA322E131C773EDE2C8B81B7
  • Return set-contract-admin (multisig → original): 4880E1E2A19CED52D67566B095324839E5C97A575E8F869B7CF613D561A60851

Shipped artifacts (MR !979, merged)

  • docs/runbooks/governance-key-rotation.md — rotation cookbook + evidence template
  • scripts/rehearse-governance-key-rotation.sh — self-restoring LocalTerra rehearsal
  • scripts/check_governance_key_rotation_docs.py, scripts/qa/verify-issue-408.sh
  • skills/AGENTS_GOVERNANCE_KEY_ROTATION.md
  • Cross-links from wasm-admin-migration.md, launch-checklist.md, key-custody.md

Launch gate note

The automated LocalTerra rehearsal proves signing flow and message shapes. Production go/no-go still requires repeating rotation from the planned production multisig on testnet/staging once that ceremony is complete (per runbook §6 and PlasticDigits' multisig address comment).

Closing — all acceptance criteria satisfied on main.

## Implementation verification (#408 / SEC-D10) Verified on `main` (post-!979). No additional code/doc changes were required in this pass. ### Acceptance criteria | Criterion | How verified | Result | |-----------|--------------|--------| | Rotation runbook with copy-pastable commands | `docs/runbooks/governance-key-rotation.md` — `set-contract-admin`, `update_config`, multisig flow, post-rotation queries | **PASS** | | Multisig threshold + signers (or private reference) | Runbook §5 → `docs/runbooks/key-custody.md` (SEC-B10); production multisig `terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7` in `docs/reference/governance-multisig.md` | **PASS** | | Rehearsal record / LocalTerra transcript | `make verify-issue-408` step [5] — live round-trip on fresh LocalTerra deploy | **PASS** | | DEX-P2-026 closed with runbook link | `docs/reviews/20260409T030009Z/ISSUE_BACKLOG.md` — marked shipped → `governance-key-rotation.md` | **PASS** | ### Commands run ```bash make check-governance-key-rotation-docs # OK make verify-issue-408 # PASS: 5 FAIL: 0 SKIP: 0 ``` LocalTerra rehearsal (from `make verify-issue-408`): - Factory: `terra1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3ysc6mpf5` - Original admin (restored): `terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v` - Rehearsal multisig (2-of-3): `terra1hs6jfpxltzcyask9e3zmkfugydvngh4dyer3sz` - Forward `set-contract-admin` (key → multisig): `E5710AFECC973F1820226DD1485145E4E8CCDC97FA322E131C773EDE2C8B81B7` - Return `set-contract-admin` (multisig → original): `4880E1E2A19CED52D67566B095324839E5C97A575E8F869B7CF613D561A60851` ### Shipped artifacts (MR !979, merged) - `docs/runbooks/governance-key-rotation.md` — rotation cookbook + evidence template - `scripts/rehearse-governance-key-rotation.sh` — self-restoring LocalTerra rehearsal - `scripts/check_governance_key_rotation_docs.py`, `scripts/qa/verify-issue-408.sh` - `skills/AGENTS_GOVERNANCE_KEY_ROTATION.md` - Cross-links from `wasm-admin-migration.md`, `launch-checklist.md`, `key-custody.md` ### Launch gate note The automated LocalTerra rehearsal proves signing flow and message shapes. **Production go/no-go** still requires repeating rotation from the planned production multisig on testnet/staging once that ceremony is complete (per runbook §6 and PlasticDigits' multisig address comment). Closing — all acceptance criteria satisfied on `main`.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-07-01 06:52:26 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#408
No description provided.