Skip to content

Replace simple wallet lookup with cryptographic proof-of-membership verification #173

Description

@Lakes41

Replace simple wallet lookup with cryptographic proof-of-membership verification

Difficulty: Expert
Type: Security

Background: app/api/verify/route.ts's live-mode path calls client.verifyWallet(discordUserId, wallet), which — based on IntegrationClient's contract — presumably performs a lookup-style verification (does this Discord user's claimed wallet exist and hold a valid membership?) rather than a cryptographic proof that the requester actually controls the claimed wallet.

Problem: A lookup-style verification is vulnerable to a user simply claiming someone else's public wallet address (all Ethereum addresses are public) to fraudulently gain access to that wallet's associated roles/passes, since nothing in the flow proves the requester — not just the address — controls the private key.

Expected outcome: /api/verify (and the underlying IntegrationClient.verifyWallet contract) is upgraded to a genuine challenge-response cryptographic proof: the server issues a single-use nonce/challenge, the client signs it with the claimed wallet's private key (e.g. via the same wallet-connection flow as #38's SIWE work), and only a valid signature over that specific challenge is accepted as proof of control — closing the address-spoofing gap.

Suggested implementation:

  • Add a nonce-issuance step to the verification flow (reusable with feat: implement production-ready webhook verification utilities #38's SIWE nonce infrastructure if implemented, or standalone otherwise), tied to the specific (discordUserId, wallet) pair being verified to prevent cross-context replay.
  • Update /api/verify/route.ts to require and cryptographically verify a signature over the issued challenge (using viem's signature verification utilities) before calling through to IntegrationClient/recording a verified membership.
  • Update the Discord bot's verification command flow (wherever it currently prompts a user to submit a wallet) to guide the user through signing the challenge, not just pasting an address.
  • Ensure nonces are single-use, scoped, and time-limited, with replay attempts explicitly rejected and logged.

Acceptance criteria:

  • A verification request with a claimed wallet but no valid signature over the issued challenge is rejected.
  • A verification request with a valid signature over the correct challenge for that (discordUserId, wallet) pair succeeds.
  • A replayed or cross-context signature (valid for a different challenge or different Discord user) is rejected.
  • verify.test.ts/live-verify.test.ts are extended to cover unsigned, wrongly-signed, and replayed-signature scenarios.

Likely affected files: apps/dashboard/app/api/verify/route.ts, packages/integration-client/src/client.ts, apps/discord-bot/src/index.ts, apps/dashboard/test/verify.test.ts

Labels: security, feature, help wanted, priority: high, GrantFox OSS, Maybe Rewarded, Official Campaign | FWC26


Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSGrantFox Open Source Sponsorship program tagMaybe RewardedIssue may qualify for a reward upon successful completion per campaign rulesOfficial Campaign | FWC26Official FWC26 campaign issue — eligible for campaign scoring and rewardsfeatureNew feature, enhancement, or functional additionhelp wantedExtra attention is neededpriority: highpriority: highsecuritySecurity-related fix, hardening, audit, or vulnerability remediation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions