Skip to content

critical: parameters multisig is decorative — admin bypass, stale approvals, self-updatable signers #107

Description

@grantfox-oss

Problem

Three flaws combine to make the parameters-contract multisig (contracts/parameters-contract/src/lib.rs) provide theater, not security:

  1. Admin bypass: configure_multisig() (lines 41–57) requires only the single admin key's auth. The same admin retains do_set_admin() reachability through proposals AND direct set_admin-style power elsewhere in the protocol. A single compromised key can reconfigure or sidestep the entire "multisig".
  2. Stale approvals survive signer-set changes: proposals store approvals: Vec<Address> (lines 79–91). If UpdateSigners executes and removes a signer, that removed signer's approval remains counted by execute() (line 132 checks only approvals.len() >= threshold). Revoked signers retain veto/exec power over in-flight proposals.
  3. Self-serving threshold reduction: a signer set at threshold 2-of-3 can propose UpdateSigners to 2-of-2 (or admit a colluder); execute() validates against the CURRENT config, so the proposal needs only old-threshold approvals to install a weaker future threshold. There is no escalation guard requiring higher quorum for signer-set changes.

Combined: one colluding signer plus one stale approval can rewrite parameters (interest bps, min guarantee, grace periods) that directly control creditline economics.

Ground Rules

  1. Read context/architecture-context.md, context/code-standards.md, context/progress-tracker.md in full
  2. Read parameters-contract in full including storage.rs and types.rs (MultisigConfig, Proposal)
  3. Preserve the existing event surface where possible; additive changes only

What To Build

  1. Record the snapshot of eligible signer addresses (not just a count) at proposal time; approve() and execute() must validate each approver against the snapshot AND current membership, rejecting anyone removed since.
  2. Require a strictly higher quorum for UpdateSigners actions (e.g. threshold + 1 or full unanimity — pick and document one) so signers cannot cheapen their own gate.
  3. On configure_multisig, emit a prominent event and consider a two-step confirmation (propose→confirm) so a single admin key cannot silently swap the signer set.
  4. Clear/re-validate in-flight proposals whose action targets the signer set when the signer set changes.
  5. Tests for every branch above, including the stale-approval exploit reproducing end-to-end before the fix and failing after.

Files To Touch

  • contracts/parameters-contract/src/lib.rs
  • contracts/parameters-contract/src/storage.rs
  • contracts/parameters-contract/src/types.rs
  • contracts/parameters-contract/src/tests.rs
  • context/progress-tracker.md

Acceptance Criteria

  • Removed signers' approvals are never counted
  • Signer-set changes require elevated quorum
  • Exploit reproduction test exists and fails pre-fix / passes post-fix semantics documented in the PR
  • Build zero errors, all tests green

Mandatory Checks Before Opening PR

  • All context/ files read and understood
  • Code follows context/code-standards.md exactly
  • progress-tracker updated
  • New tests added; suite green
  • PR references this issue number exactly

PRs failing any check will be closed without review.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions