Security: admin-key custody missing named signer list, backup signer, and rotation process [SEC-B10] #398

Closed
opened 2026-06-19 10:41:35 +00:00 by totdking · 11 comments
totdking commented 2026-06-19 10:41:35 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-19 10:42:17 +00:00 (Migrated from gitlab.com)

Checklist Item

SEC-B10: Document admin-key custody for small launch: multisig preferred, named backup signer, no single hot wallet for mainnet if avoidable. Verify: deployment runbook has signer list and rotation process.


Summary

The security model and launch checklist require that governance be a multisig with no single hot wallet on mainnet. The requirement exists as a policy statement in multiple places but no document provides a named signer list, a designated backup signer, or a key rotation process.


What Was Checked

  • docs/security-model.md line 17 -- "governance address should be a multisig or DAO-controlled address in production. Never use a single EOA for mainnet governance" -- policy only, no names
  • docs/runbooks/launch-checklist.md Phase 0 line 13 -- checklist item requires multisig for governance and treasury, item unchecked
  • docs/runbooks/wasm-admin-migration.md -- migration procedures only, no signer list or rotation steps
  • docs/deployment-guide.md -- contract deployment commands only, no key custody section
  • docs/operator-secrets.md lines 47-49 -- "Multisig governance for factory/router/pair admin is required for production" -- no names, no rotation
  • CODEOWNERS -- only @PlasticDigits listed, no multisig member roster

Expected (per checklist)

The deployment runbook or a linked custody document must include: the planned multisig type and threshold, named roles for each required signer, a designated backup signer, a key rotation process (conditions and steps), and a statement that no single hot wallet controls mainnet governance.


Actual

The requirement exists as a policy statement across three files but no implementation details exist anywhere in the repo. No signer names, roles, threshold configuration, backup designation, or rotation schedule are documented.


Evidence

  • docs/security-model.md line 17: policy requirement only
  • docs/operator-secrets.md lines 47-49: policy requirement only
  • docs/runbooks/launch-checklist.md line 13: checklist item not yet completed
  • CODEOWNERS: only @PlasticDigits, no multisig member list

Suggested Fix

Add a custody section to docs/runbooks/launch-checklist.md or a separate docs/runbooks/key-custody.md covering:

  • Multisig type (e.g. Cosmos multisig, Gnosis Safe, DAO proposal) and signing threshold
  • Named roles for each signer (role title, not necessarily personal names if kept private)
  • Backup signer designation and escalation path if primary signers are unavailable
  • Key rotation trigger conditions and rotation steps
  • Statement that no single EOA holds governance key material for mainnet

This document does not need to be public but must be linked from the launch runbook so it is reachable during an incident.


Verification Checklist

  • Multisig type and threshold are documented
  • Named signer roles are documented (internal doc linked from runbook is acceptable)
  • Backup signer and escalation path are designated
  • Key rotation trigger conditions and process are documented
  • No single EOA governance statement is included
  • Phase 0 checklist item in docs/runbooks/launch-checklist.md is completed with a reference to the custody doc

Labels

security, pre-launch

Cc: @PlasticDigits

### Checklist Item SEC-B10: Document admin-key custody for small launch: multisig preferred, named backup signer, no single hot wallet for mainnet if avoidable. Verify: deployment runbook has signer list and rotation process. --- ### Summary The security model and launch checklist require that governance be a multisig with no single hot wallet on mainnet. The requirement exists as a policy statement in multiple places but no document provides a named signer list, a designated backup signer, or a key rotation process. --- ### What Was Checked - `docs/security-model.md` line 17 -- "governance address should be a multisig or DAO-controlled address in production. Never use a single EOA for mainnet governance" -- policy only, no names - `docs/runbooks/launch-checklist.md` Phase 0 line 13 -- checklist item requires multisig for governance and treasury, item unchecked - `docs/runbooks/wasm-admin-migration.md` -- migration procedures only, no signer list or rotation steps - `docs/deployment-guide.md` -- contract deployment commands only, no key custody section - `docs/operator-secrets.md` lines 47-49 -- "Multisig governance for factory/router/pair admin is required for production" -- no names, no rotation - `CODEOWNERS` -- only `@PlasticDigits` listed, no multisig member roster --- ### Expected (per checklist) The deployment runbook or a linked custody document must include: the planned multisig type and threshold, named roles for each required signer, a designated backup signer, a key rotation process (conditions and steps), and a statement that no single hot wallet controls mainnet governance. --- ### Actual The requirement exists as a policy statement across three files but no implementation details exist anywhere in the repo. No signer names, roles, threshold configuration, backup designation, or rotation schedule are documented. --- ### Evidence - `docs/security-model.md` line 17: policy requirement only - `docs/operator-secrets.md` lines 47-49: policy requirement only - `docs/runbooks/launch-checklist.md` line 13: checklist item not yet completed - `CODEOWNERS`: only `@PlasticDigits`, no multisig member list --- ### Suggested Fix Add a custody section to `docs/runbooks/launch-checklist.md` or a separate `docs/runbooks/key-custody.md` covering: - Multisig type (e.g. Cosmos multisig, Gnosis Safe, DAO proposal) and signing threshold - Named roles for each signer (role title, not necessarily personal names if kept private) - Backup signer designation and escalation path if primary signers are unavailable - Key rotation trigger conditions and rotation steps - Statement that no single EOA holds governance key material for mainnet This document does not need to be public but must be linked from the launch runbook so it is reachable during an incident. --- ### Verification Checklist - [ ] Multisig type and threshold are documented - [ ] Named signer roles are documented (internal doc linked from runbook is acceptable) - [ ] Backup signer and escalation path are designated - [ ] Key rotation trigger conditions and process are documented - [ ] No single EOA governance statement is included - [ ] Phase 0 checklist item in `docs/runbooks/launch-checklist.md` is completed with a reference to the custody doc --- ### Labels `security`, `pre-launch` Cc: @PlasticDigits
PlasticDigits commented 2026-06-19 10:51:00 +00:00 (Migrated from gitlab.com)

Pending multisig setup

Pending multisig setup
totdking commented 2026-06-19 10:57:16 +00:00 (Migrated from gitlab.com)

mentioned in issue #381

mentioned in issue #381
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:05 +00:00 (Migrated from gitlab.com)

Picked up SEC-B10 and wrote the custody runbook + wired it in. MR !978, branch issue-398-key-custody-roster, commit f1091f01.

New docs/runbooks/key-custody.md covers the whole checklist:

  • multisig type + threshold — k-of-n Cosmos multisig (or DAO), with a minimum-threshold table by TVL band (2-of-3 bootstrap, 3-of-5 growth, >=3-of-5 + timelock mature)
  • signer roster by role (primary governance / treasury / security / backup) — roles only; identities stay in the private key store, not committed
  • backup signer + escalation path (signer-unavailable, suspected-compromise -> rotate, unrecoverable-threshold)
  • key-rotation triggers + process (compromise / departure / scheduled / threshold change, then generate -> set-contract-admin + factory UpdateConfig { governance } -> threshold-sign -> verify on chain -> retire old keys)
  • "no single EOA" stated in the intro, policy, and rotation sections

Kept it from stepping on the neighbors: it points at SEC-B09/#397 for the actual multisig signing flow and forward-refs SEC-D10/#408 for the copy-paste rotation cookbook + LocalTerra rehearsal, so nothing's duplicated.

Wiring: completed the Phase 0 custody item in the launch checklist (links the runbook, SEC-B10, make verify-issue-398), added it to the Related-docs header, the Admin-controls BLOCK row, and the go/no-go doc-invariant block, plus a cross-link from the security model. Added the usual guard set — check_key_custody_docs.py, verify-issue-398.sh, AGENTS_KEY_CUSTODY.md, Makefile targets into lint + help.

make verify-issue-398 -> 5/5; the drift guard fails closed on a missing file or stripped marker, and every section anchor resolves.

One thing I deliberately did NOT do: left the Phase 0 checkbox unchecked and invented no signer names, addresses, or final threshold — that's your "pending multisig setup". The runbook says outright not to treat the custody gate as satisfied until the real multisig is generated and live, and the filled roster gets linked privately off #391. So the docs side is good to merge/close from my side; the actual gate flips once the ceremony's done.

Needs your review + merge. @PlasticDigits

Picked up SEC-B10 and wrote the custody runbook + wired it in. MR !978, branch `issue-398-key-custody-roster`, commit `f1091f01`. New `docs/runbooks/key-custody.md` covers the whole checklist: - multisig type + threshold — `k-of-n` Cosmos multisig (or DAO), with a minimum-threshold table by TVL band (2-of-3 bootstrap, 3-of-5 growth, >=3-of-5 + timelock mature) - signer roster by role (primary governance / treasury / security / backup) — roles only; identities stay in the private key store, not committed - backup signer + escalation path (signer-unavailable, suspected-compromise -> rotate, unrecoverable-threshold) - key-rotation triggers + process (compromise / departure / scheduled / threshold change, then generate -> `set-contract-admin` + factory `UpdateConfig { governance }` -> threshold-sign -> verify on chain -> retire old keys) - "no single EOA" stated in the intro, policy, and rotation sections Kept it from stepping on the neighbors: it points at SEC-B09/#397 for the actual multisig signing flow and forward-refs SEC-D10/#408 for the copy-paste rotation cookbook + LocalTerra rehearsal, so nothing's duplicated. Wiring: completed the Phase 0 custody item in the launch checklist (links the runbook, SEC-B10, `make verify-issue-398`), added it to the Related-docs header, the Admin-controls BLOCK row, and the go/no-go doc-invariant block, plus a cross-link from the security model. Added the usual guard set — `check_key_custody_docs.py`, `verify-issue-398.sh`, `AGENTS_KEY_CUSTODY.md`, Makefile targets into `lint` + `help`. `make verify-issue-398` -> 5/5; the drift guard fails closed on a missing file or stripped marker, and every section anchor resolves. One thing I deliberately did NOT do: left the Phase 0 checkbox unchecked and invented no signer names, addresses, or final threshold — that's your "pending multisig setup". The runbook says outright not to treat the custody gate as satisfied until the real multisig is generated and live, and the filled roster gets linked privately off #391. So the docs side is good to merge/close from my side; the actual gate flips once the ceremony's done. Needs your review + merge. @PlasticDigits
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:08 +00:00 (Migrated from gitlab.com)

mentioned in issue #408

mentioned in issue #408
PlasticDigits commented 2026-06-30 14:50:46 +00:00 (Migrated from gitlab.com)

mentioned in commit f1125d59c9

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

terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7

terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7
PlasticDigits commented 2026-07-01 06:31:26 +00:00 (Migrated from gitlab.com)

SEC-B10 (#398) — verification complete

All acceptance criteria for the documentation/custody framework deliverable are satisfied on main (MR !978 merged; canonical multisig address terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7 recorded in docs/reference/governance-multisig.md and cross-linked from the custody runbook).

Acceptance checklist

Criterion Verification Result
Multisig type and threshold documented docs/runbooks/key-custody.md §1 (k-of-n Cosmos multisig, TVL-banded minimum thresholds) PASS
Named signer roles documented docs/runbooks/key-custody.md §2 (primary governance / treasury / security / backup roles; private fill-in at key ceremony) PASS
Backup signer + escalation path docs/runbooks/key-custody.md §3 PASS
Key rotation triggers and process docs/runbooks/key-custody.md §4 (+ forward-ref to SEC-D10 / #408) PASS
No single EOA governance statement Policy section + §4 in key-custody.md; docs/security-model.md cross-link PASS
Phase 0 launch checklist references custody doc docs/runbooks/launch-checklist.md Phase 0 item links key-custody.md, SEC-B10, make verify-issue-398 PASS

Commands run (2026-07-01)

make verify-issue-398          # 5/5 PASS
make check-key-custody-docs    # OK
make lint                      # includes check_key_custody_docs.py — OK

Artifacts

  • docs/runbooks/key-custody.md — custody framework runbook
  • docs/reference/governance-multisig.md — canonical on-chain address
  • skills/AGENTS_KEY_CUSTODY.md — agent playbook
  • scripts/check_key_custody_docs.py + scripts/qa/verify-issue-398.sh — drift guards
  • Makefile targets: check-key-custody-docs, verify-issue-398 (wired into lint + help)

Operational note (not blocking #398)

The Phase 0 checkbox in launch-checklist.md remains unchecked until the key ceremony fills the private roster (signer identities, final k, emergency rehearsals from the live multisig). That is the launch gate (#391), not this documentation issue.

Closing #398 — the repo deliverable for SEC-B10 is complete.

## SEC-B10 (#398) — verification complete All acceptance criteria for the **documentation/custody framework** deliverable are satisfied on `main` (MR !978 merged; canonical multisig address `terra1zlmv2xydxcusurtr6rl78wsvytdc6mfex6hep7` recorded in `docs/reference/governance-multisig.md` and cross-linked from the custody runbook). ### Acceptance checklist | Criterion | Verification | Result | |-----------|--------------|--------| | Multisig type and threshold documented | `docs/runbooks/key-custody.md` §1 (k-of-n Cosmos multisig, TVL-banded minimum thresholds) | **PASS** | | Named signer roles documented | `docs/runbooks/key-custody.md` §2 (primary governance / treasury / security / backup roles; private fill-in at key ceremony) | **PASS** | | Backup signer + escalation path | `docs/runbooks/key-custody.md` §3 | **PASS** | | Key rotation triggers and process | `docs/runbooks/key-custody.md` §4 (+ forward-ref to SEC-D10 / #408) | **PASS** | | No single EOA governance statement | Policy section + §4 in `key-custody.md`; `docs/security-model.md` cross-link | **PASS** | | Phase 0 launch checklist references custody doc | `docs/runbooks/launch-checklist.md` Phase 0 item links `key-custody.md`, SEC-B10, `make verify-issue-398` | **PASS** | ### Commands run (2026-07-01) ```bash make verify-issue-398 # 5/5 PASS make check-key-custody-docs # OK make lint # includes check_key_custody_docs.py — OK ``` ### Artifacts - `docs/runbooks/key-custody.md` — custody framework runbook - `docs/reference/governance-multisig.md` — canonical on-chain address - `skills/AGENTS_KEY_CUSTODY.md` — agent playbook - `scripts/check_key_custody_docs.py` + `scripts/qa/verify-issue-398.sh` — drift guards - Makefile targets: `check-key-custody-docs`, `verify-issue-398` (wired into `lint` + `help`) ### Operational note (not blocking #398) The Phase 0 **checkbox** in `launch-checklist.md` remains **unchecked** until the key ceremony fills the private roster (signer identities, final `k`, emergency rehearsals from the live multisig). That is the launch gate ([#391](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/391)), not this documentation issue. Closing #398 — the repo deliverable for SEC-B10 is complete.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-07-01 06:31:27 +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#398
No description provided.