Skip to content

fix: Verify governance voting power server-side#177

Open
GranusClarvis wants to merge 1 commit intoInverseAltruism:devfrom
GranusClarvis:feature/governance-voting-power-verification
Open

fix: Verify governance voting power server-side#177
GranusClarvis wants to merge 1 commit intoInverseAltruism:devfrom
GranusClarvis:feature/governance-voting-power-verification

Conversation

@GranusClarvis
Copy link
Collaborator

Summary

  • Fixes critical security vulnerability: The governance vote endpoint previously accepted votingPower directly from the client POST body without any server-side verification. An attacker could submit votingPower: 9999 to inflate their vote count, completely undermining DAO governance integrity.
  • Adds Star holder gate for proposal creation: Previously any connected wallet could create governance proposals. Now only Star Skrumpey holders can create proposals, matching the DAO's design intent.
  • Voting power is now verified on-chain: Calls checkStarOwnershipBatched() to count actual Star Skrumpey NFT ownership before recording votes. This leverages the existing 30-second ownership cache to minimize RPC overhead.

What Changed

app/api/governance/route.ts:

  1. Vote action (line ~554-576): Replaced parseInt(votingPower, 10) || 1 (client-supplied) with server-side checkStarOwnershipBatched() call. Non-holders are rejected with 403.
  2. Proposal creation (line ~334-340): Added checkStarOwnershipBatched() gate before proposal creation. Non-holders are rejected with 403.
  3. Removed unused votingPower and typedData from request body destructuring.

Test plan

  • npm run type-check — passes
  • npm run test — 69/69 tests pass
  • npm run build — builds successfully (49 routes)
  • No new lint errors introduced (only pre-existing any type on line 500)
  • Manual test: attempt to vote with a wallet holding 0 Stars → should get 403
  • Manual test: vote with a Star holder wallet → voting power should equal actual Star count
  • Manual test: create proposal with non-holder wallet → should get 403

🤖 Generated with Claude Code

…lient

Previously, the governance vote endpoint accepted `votingPower` directly
from the client POST body without server-side verification. This allowed
any voter to claim arbitrary voting power (e.g., votingPower: 9999) when
the system's design is 1 Star Skrumpey = 1 Vote.

Changes:
- Vote action now calls checkStarOwnershipBatched() to verify actual Star
  Skrumpey ownership on-chain before recording the vote
- Voters with 0 Stars are rejected with a 403 error
- Proposal creation now requires Star holder status (was wallet-auth only)
- Removed unused client-supplied votingPower from destructuring

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant