Skip to content

Add signature-based integrity verification to QR access-check payloads #244

Description

@Lakes41

Difficulty: Advanced
Type: security

Background
The documented QR payload schema (type, version, guildId, resourceId, optional walletAddress/expiresAt) is plain JSON with format/expiry validation, but no described cryptographic integrity check — anyone who can generate JSON in this shape could produce a QR code the app will accept as a legitimate access-check request.

Problem
Without an integrity/authenticity check, a forged or tampered QR code (e.g., with a manipulated expiresAt to appear not-yet-expired, or a resourceId swapped to something the presenter doesn't actually have rights to trigger) is indistinguishable from a legitimately-issued one at the point of scanning, since access is ultimately re-verified server-side but a malicious payload could still mislead the scanning user or waste access-check calls maliciously.

Expected outcome
QR payloads include a signature field (e.g., an HMAC or ECDSA signature over the canonical payload, issued by the backend/guild admin tooling that generates the QR) that the mobile app verifies locally before even submitting an access check, rejecting unsigned or invalidly-signed payloads with a clear "Untrusted QR code" message — while remaining backward-compatible (or explicitly versioned) with the existing unsigned version: 1 payloads.

Suggested implementation

  • Design a version: 2 payload schema adding a signature field, with a documented canonicalization rule for what exactly gets signed (field order, encoding).
  • Implement local signature verification in src/features/access/ using a public key or shared verification approach appropriate for the signing method chosen (document the key-distribution approach, e.g., embedded public key vs. fetched from the backend on app start, with tradeoffs).
  • Ensure version: 1 (unsigned) payloads either continue to be accepted with a clear "unverified" indicator, or are rejected outright — decide and document the policy explicitly, since this is a meaningful security/compatibility tradeoff.
  • Add a "Signature verified ✓" / "Untrusted QR code" distinct UI state on the scanner screen.
  • Write thorough unit tests: valid signature, tampered payload with a stale signature, missing signature under the new policy, and the version: 1 compatibility decision.
  • Document the new payload version and signing scheme in the README's "QR access check payload" section and in docs/.

Acceptance criteria

  • version: 2 payloads with a valid signature are accepted and clearly marked as verified
  • Tampered payloads (valid signature over different original content) are rejected
  • The version: 1 compatibility policy is explicitly implemented and documented, not left ambiguous
  • README and docs/ updated with the new schema and key-distribution approach

Likely affected files/directories

  • src/features/access/
  • app/access-scanner.tsx
  • docs/
  • README.md

Metadata

Metadata

Assignees

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 rewardsadvancedAdvanced difficulty tasks requiring significant domain knowledge and implementation effortsecuritySecurity-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