Skip to content

[governance-dao] finalize() refunds config.proposal_threshold from live config not the amount locked at creation — admin can steal proposer deposit by changing config #137

Description

@nonsobethel0-dev

Summary

In contracts/governance-dao/src/lib.rs, create_proposal() locks config.proposal_threshold tokens from the proposer. finalize() refunds config.proposal_threshold by reading the live config at finalization time — not the amount that was originally deposited.

Code

create_proposal (line 129): deposits current threshold

gov_token.transfer(&proposer, &env.current_contract_address(), &config.proposal_threshold);

finalize (line 251): refunds current threshold

let config: DaoConfig = env.storage().instance().get(&StorageKey::Config).unwrap();
gov_token.transfer(&env.current_contract_address(), &proposal.proposer, &config.proposal_threshold);
// ↑ uses live config.proposal_threshold, not what was deposited

Attack Scenarios

Scenario A — Admin steals proposer tokens:

  1. Proposer locks 1,000 SHIELD at creation (threshold = 1,000)
  2. Admin calls update_config setting threshold = 1 (before voting ends)
  3. finalize refunds only 1 SHIELD — proposer loses 999 SHIELD

Scenario B — Proposer extracts excess tokens:

  1. Proposer locks 100 SHIELD (threshold = 100)
  2. Admin raises threshold to 10,000 before finalize
  3. finalize attempts to transfer 10,000 SHIELD — will panic if contract has < 10,000

Fix

Store the deposited amount on the Proposal struct at creation and refund that exact amount:

// In Proposal struct
pub deposit: i128,

// In create_proposal
let deposit = config.proposal_threshold;
gov_token.transfer(&proposer, &env.current_contract_address(), &deposit);
let proposal = Proposal { ..., deposit, ... };

// In finalize
gov_token.transfer(&env.current_contract_address(), &proposal.proposer, &proposal.deposit);

Severity: High

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions