Root docs
Repository viewer
Legacy docs parity surface
Back to repository viewer
Repository document

Threat Model

threat-model.md

Boundary

This route preserves legacy markdown access inside the Next.js surface. The raw repository file remains authoritative.

Open raw file

Threat Model

1. System Overview

PrivateDAO is a Solana governance protocol implemented as an Anchor program. It governs proposal creation, hidden voting, proposal finalization, and treasury execution.

The core lifecycle is:

  • `create_proposal`
  • `commit_vote` or `commit_delegated_vote`
  • `reveal_vote`
  • `finalize_proposal`
  • `execute_proposal`

The commit-reveal flow is intentional:

  • votes are committed as `sha256(vote_byte || salt_32 || proposal_pubkey_32 || voter_pubkey_32)`
  • the proposal tally remains hidden during the commit phase
  • tally updates only after valid reveal
  • execution is separated from finalization by a timelock

Treasury execution supports:

  • `SendSol`
  • `SendToken`
  • `CustomCPI` as a reserved action type that is rejected rather than exposed as arbitrary on-chain CPI execution

Delegation is proposal-scoped:

  • a delegator can delegate voting weight to a delegatee for one proposal
  • the delegatee commits and reveals using combined weight
  • delegation is one-shot through `is_used`

On-chain boundaries:

  • DAO, proposal, voter record, delegation, treasury, and voter-weight accounts
  • instruction-phase enforcement
  • signer enforcement
  • PDA and account binding enforcement
  • treasury movement

Off-chain boundaries:

  • CLI scripts
  • GitHub Pages frontend
  • Android-native client
  • RPC availability
  • wallet signing
  • zk witness generation
  • zk proving
  • zk verification artifacts

The protocol is on-chain for state transition and treasury safety. Operator surfaces are off-chain wrappers around that protocol.

The current zk layer is additive:

  • it does not change the deployed on-chain lifecycle
  • it adds a real off-chain proof path
  • it introduces new proof-system assumptions that must be reviewed separately

2. Actor Model

Malicious voter

Capabilities:

  • holds governance tokens
  • can sign transactions
  • can attempt invalid commit/reveal orderings
  • can attempt replay, wrong salt, wrong vote payload, or late reveal
  • can attempt voter-record substitution

Malicious delegate

Capabilities:

  • acts as delegatee on a proposal
  • can attempt to consume delegated rights outside intended binding
  • can attempt stale or cross-proposal delegation use
  • can attempt overlap with direct commit paths

Malicious treasury participant

Capabilities:

  • attempts treasury account substitution
  • attempts recipient substitution
  • attempts wrong mint, wrong token source, wrong token destination, or duplicate token account wiring
  • attempts to trigger execution with valid-looking but semantically wrong accounts

Compromised signer

Capabilities:

  • controls a wallet with governance tokens or authority privileges
  • can submit otherwise valid instructions
  • can attempt to finalize or execute in unexpected order
  • can exploit any missing signer/account binding checks

Account substitution attacker

Capabilities:

  • supplies initialized accounts that are structurally valid
  • swaps proposal, voter record, delegation, treasury, or token accounts
  • attempts semantic confusion without breaking serialization

Replay attacker

Capabilities:

  • resubmits prior instructions
  • reuses signatures only at the transaction layer if possible
  • attempts repeated commit, reveal, finalize, or execute
  • attempts reordered or slightly altered account sets against old state

Confused-deputy attacker

Capabilities:

  • uses a permissionless surface such as finalize or execute
  • supplies valid signer but mismatched account context
  • relies on protocol accepting approximate authority or account relations

External transaction manipulator

Capabilities:

  • observes transaction timing
  • front-runs or back-runs around timing windows
  • cannot forge signatures, but can exploit timing or account assumptions if they exist

ZK artifact attacker

Capabilities:

  • attempts to substitute public signals
  • attempts to rely on reviewer confusion between current on-chain logic and future zk integration
  • attempts to exploit incorrect setup, verification key, or proof-handling assumptions

3. Asset Model

Treasury balances

Treasury SOL and SPL token balances must not move except through correctly finalized and correctly wired execution paths.

Governance decision correctness

A proposal outcome must reflect valid committed and revealed votes, not invalid reveals, stale delegation, or state confusion.

Proposal lifecycle integrity

A proposal must move only through valid lifecycle states and must not skip, regress, or duplicate critical transitions.

Voter rights

Only valid governance token holders should be able to propose or vote with the weight they legitimately control.

Delegation rights

Delegation must remain proposal-scoped, delegatee-bound, one-shot, and non-replayable in practical operation.

Execution correctness

Execution must move the intended asset to the intended recipient only after the intended proposal has passed and unlocked.

Proposal status invariants

`Voting`, `Passed`, `Failed`, `Cancelled`, and `Vetoed` statuses must remain consistent with the lifecycle and must not be entered through partial or confused paths.

ZK proof integrity

Proof artifacts, verification keys, and public signals must correspond to the intended circuit semantics. Otherwise the zk layer would create false assurance rather than stronger privacy guarantees.

4. Attack Surfaces

Create proposal

Misuse risks:

  • proposer without token ownership
  • malformed treasury action
  • wrong proposer token mint

Commit vote

Misuse risks:

  • vote from zero-balance or insufficient-balance account
  • double commit
  • commit after voting close
  • wrong voter record or wrong proposal binding

Commit delegated vote

Misuse risks:

  • non-delegatee consuming delegated rights
  • delegation from another proposal
  • replaying a used delegation
  • cross-proposal account confusion

Reveal vote

Misuse risks:

  • reveal before commit
  • reveal with wrong salt
  • reveal with wrong vote payload
  • reveal by wrong signer
  • reveal after reveal window
  • reveal against wrong proposal or wrong voter record

Finalize proposal

Misuse risks:

  • finalize before reveal window ends
  • finalize with wrong DAO / proposal pairing
  • finalize after proposal is already finalized
  • confused-deputy use of permissionless finalize surface

Execute proposal

Misuse risks:

  • execute before finalization
  • execute before timelock unlock
  • execute twice
  • execute with wrong treasury PDA
  • execute with wrong recipient
  • execute with wrong token mint or token ownership relations
  • partial mutation before CPI failure

Treasury transfer logic

Misuse risks:

  • SOL recipient substitution
  • token mint mismatch
  • source account not controlled by treasury PDA
  • destination account not owned by intended recipient
  • duplicate token source/destination

Delegation logic

Misuse risks:

  • self-delegation
  • stale delegation
  • cross-proposal reuse
  • overlap between delegated and direct voting paths

Timing window transitions

Misuse risks:

  • off-by-one mistakes at commit end
  • off-by-one mistakes at reveal start/end
  • premature finalization
  • premature execution

ZK companion-proof path

Misuse risks:

  • treating zk as if it already changes the deployed protocol when it does not
  • mismatching proof public signals with the intended DAO or proposal context
  • stale proof artifact reuse in review or verification flows
  • verification-key confusion

5. Threat Classes

Lifecycle bypass

Attempting to finalize or execute from the wrong phase or from a proposal state that is not eligible for that transition.

Replay attacks

Attempting to repeat a previously valid lifecycle step to duplicate effects or re-enter a phase.

Duplicate execution

Attempting to move treasury funds more than once from the same proposal.

Signer confusion

Using a signer that is valid for transaction submission but not valid for the protocol role intended by the account set.

Authority misuse

Attempting to use authority-only paths or authority-related account expectations with the wrong signer or wrong DAO context.

PDA substitution

Supplying a valid account that is not the PDA derived for the intended proposal, vote record, delegation, or treasury.

Account misbinding

Supplying accounts that are individually valid but belong to a different proposal, DAO, delegation, or recipient relationship.

Treasury miswiring

Supplying incorrect treasury, recipient, token source, or token destination accounts to extract funds or redirect them.

Commit-reveal mismatch

Attempting to reveal a vote that does not match the stored commitment or stored voter identity.

Invalid reveal injection

Attempting to reveal before commit, after the reveal window, or using a wrong signer or keeper.

Timing boundary attacks

Attempting to exploit off-by-one mistakes around `voting_end`, `reveal_end`, or `execution_unlocks_at`.

Delegation misuse

Attempting to reuse delegation state, consume it from the wrong signer, or apply it to the wrong proposal.

Partial state mutation

Attempting to trigger a failure after a lifecycle field or balance changes partially, leaving the protocol in an inconsistent state.

State regression

Attempting to push a proposal back into an earlier state or create impossible state combinations after failure paths.

Semantic account confusion

Supplying initialized, owner-correct, or funded accounts that still do not belong to the exact intended governance relationship.

ZK proof confusion

Treating a valid proof as if it were sufficient for a different DAO, proposal, or verifier context than the one encoded in its public signals.

6. Mitigations

Lifecycle bypass

Mitigation:

  • `commit_vote` requires `status == Voting`
  • `reveal_vote` requires `status == Voting` and timing checks
  • `finalize_proposal` requires `status == Voting` and `now >= reveal_end`
  • `execute_proposal` requires `status == Passed`, `!is_executed`, and `now >= execution_unlocks_at`

Protocol enforcement:

  • `programs/private-dao/src/lib.rs`

Tests:

  • `tests/full-flow-test.ts`
  • `tests/private-dao.ts`

Replay and duplicate execution

Mitigation:

  • voter records reject `AlreadyCommitted`
  • reveals reject `AlreadyRevealed`
  • finalize rejects `AlreadyFinalized`
  • execute rejects `AlreadyExecuted`

Protocol enforcement:

  • `programs/private-dao/src/lib.rs`

Tests:

  • `tests/private-dao.ts`
  • `tests/full-flow-test.ts`

Signer confusion and authority misuse

Mitigation:

  • authority-only paths use `has_one = authority`
  • reveal requires `revealer == voter || revealer == voter_reveal_authority`
  • delegated commit requires `delegation.delegatee == delegatee.key()`
  • finalize and execute remain permissionless, but account bindings remain strict

Protocol enforcement:

  • `CancelProposal`
  • `VetoProposal`
  • `RevealVote`
  • `CommitDelegatedVote`
  • `FinalizeProposal`
  • `ExecuteProposal`

Tests:

  • `tests/private-dao.ts`
  • `tests/full-flow-test.ts`

PDA substitution and account misbinding

Mitigation:

  • proposal accounts use proposal PDA seeds
  • voter records use vote PDA seeds bound to proposal + voter
  • delegation records use delegation PDA seeds bound to proposal + delegator
  • treasury PDA is derived from DAO
  • `has_one = dao` and seed constraints enforce exact relations

Protocol enforcement:

  • account validation in instruction contexts

Tests:

  • `tests/private-dao.ts`
  • `tests/full-flow-test.ts`

Treasury miswiring

Mitigation:

  • `SendSol` checks `treasury_recipient == action.recipient`
  • `SendToken` checks:
  • token program ownership
  • token account length sanity
  • treasury token owner equals treasury PDA
  • source mint equals action mint
  • destination mint equals action mint
  • destination owner equals configured recipient
  • source and destination are not the same account

Protocol enforcement:

  • `execute_proposal`

Tests:

  • `tests/full-flow-test.ts`

Commit-reveal mismatch and invalid reveal injection

Mitigation:

  • reveal recomputes `sha256(vote || salt || proposal_pubkey || voter_pubkey)`
  • reveal requires committed state
  • reveal rejects wrong signer and wrong timing

Protocol enforcement:

  • `reveal_vote`

Tests:

  • `tests/private-dao.ts`
  • `tests/full-flow-test.ts`

Timing boundary attacks

Mitigation:

  • explicit `< voting_end`, `>= voting_end`, `< reveal_end`, `>= execution_unlocks_at` checks
  • tests assert before/at/after transition behavior

Protocol enforcement:

  • `commit_vote`
  • `commit_delegated_vote`
  • `reveal_vote`
  • `finalize_proposal`
  • `execute_proposal`

Tests:

  • `tests/full-flow-test.ts`

Delegation misuse

Mitigation:

  • self-delegation rejected
  • delegation tied to one proposal
  • delegated commit checks delegatee equality
  • `is_used` blocks reuse after successful delegated commit
  • direct and delegated paths reject overlap on-chain through proposal-bound marker accounts

Protocol enforcement:

  • `delegate_vote`
  • `commit_delegated_vote`

Tests:

  • `tests/private-dao.ts`

Partial state mutation and state regression

Mitigation:

  • tests verify failed finalize and execute leave critical fields unchanged
  • failed treasury execution paths are asserted not to set `is_executed`
  • proposal status remains stable after failed execute attempts

Protocol enforcement:

  • Anchor transaction atomicity
  • explicit state checks around lifecycle fields

Tests:

  • `tests/full-flow-test.ts`

ZK companion-proof integrity

Mitigation:

  • public signals bind proof semantics to DAO and proposal context
  • proof verification is exposed through repository commands rather than vague claims
  • reviewer-facing docs explain the difference between current commit-reveal and zk-augmented governance
  • zk artifacts are gated through `verify-zk-surface.sh`

Protocol and repository enforcement:

  • `zk/circuits/private_dao_vote_overlay.circom`
  • `scripts/zk/build-zk.sh`
  • `scripts/zk/prove-sample.sh`
  • `scripts/zk/verify-sample.sh`
  • `scripts/verify-zk-surface.sh`

Tests / verification references:

  • `docs/zk-layer.md`
  • `docs/zk-upgrade.md`
  • `docs/zk-evidence.md`

7. Residual Risks

  • commit-reveal hides vote content, not transaction timing or participation timing
  • the zk layer is off-chain today and is not yet an on-chain verifier integration
  • `CustomCPI` is intentionally unsupported as a live execution path
  • external RPC availability and local validator behavior affect verification environments
  • no external audit is claimed
  • mainnet release operations still require release discipline, monitoring, and wallet hygiene outside the program itself

8. Trust Assumptions

Trusted or assumed components:

  • Solana runtime transaction atomicity
  • Anchor account validation and signer enforcement
  • SPL Token program correctness
  • honest wallet signature semantics
  • RPC responses are sufficiently correct for off-chain observation
  • Circom circuit correctness for the current companion stack
  • Groth16 setup artifact integrity
  • verification key integrity for the committed zk artifacts

Timing assumptions:

  • cluster time and block time progress enough for lifecycle windows to become reachable
  • users and operators do not assume sub-second exactness beyond the enforced timestamp boundaries

Operational assumptions:

  • wallets sign only intended transactions
  • off-chain surfaces preserve account sets and user intent
  • deployment and governance operations use the intended program ID and cluster