Skip to content

Resolve Unauthenticated Minting, Predictable Randomness, and Missing Rate Limits in three-card-monte - #138

Open
magqqgq wants to merge 1 commit into
base:masterfrom
magqqgq:magqqgq-patch-1
Open

Resolve Unauthenticated Minting, Predictable Randomness, and Missing Rate Limits in three-card-monte#138
magqqgq wants to merge 1 commit into
base:masterfrom
magqqgq:magqqgq-patch-1

Conversation

@magqqgq

@magqqgq magqqgq commented Sep 2, 2026

Copy link
Copy Markdown

Description

This pull request addresses findings F-03, F-11, F-12, and F-13 from the workspace security audit[cite: 30]. It completely overhauls the game logic to make rounds server-authoritative, prevents unauthorized on-chain reward minting, introduces proper rate-limiting for gas-spending endpoints, and hardens the random number generation logic against state recovery attacks.

Key Changes & Remediations

1. Server-Authoritative Reward Minting (F-03)

  • Closing the Minting Oracle: The /api/win endpoint previously accepted unsigned, unverified win claims directly from the client request body and minted rewards unconditionally[cite: 30]. This has been refactored to rely on a server-side Redis validation flow.
  • Secure State Initialization: A new route, /api/game/start, securely selects the winning card using crypto.randomInt and stores it in Redis under an unguessable 128-bit gameId[cite: 30]. The winning card is deliberately excluded from the client response[cite: 30].
  • Atomic Single-Use Gate: The claimRound logic uses a SET NX EX atomic lock to prevent concurrent replay race conditions, ensuring a round can only ever be consumed once[cite: 30].

2. Rate Limiting for Gas & Signer Endpoints (F-11)

  • Sliding-Window Implementation: A new in-memory rate limiter (lib/rate-limit.ts) has been introduced to protect the application's budget[cite: 30]. The game start endpoint is capped at 20 requests/min, while the payout endpoint is restricted to 10 requests/min.
  • Safe Cache Pruning: The rate-limit cache pruning defers deletions to avoid ES5 TS2802 Map iteration mutation errors[cite: 30].

3. Cryptographically Secure Randomness (F-12)

  • CSPRNG Implementation: Replaced the vulnerable Math.random() (which relies on xorshift128+ and is susceptible to state recovery and modulo bias) with crypto.getRandomValues() paired with explicit rejection sampling (lib/shuffle.ts)[cite: 30].

4. Error Masking (F-13)

  • Information Leakage Prevented: The app/api/win/route.ts previously returned raw error.message strings from CDP and RPC internals back to the caller[cite: 30]. All upstream errors are now logged strictly server-side and resolved to the client via generic 502 Bad Gateway or 400 Bad Request responses[cite: 30].

…Rate Limits in `three-card-monte`

### Description
This pull request addresses findings F-03, F-11, F-12, and F-13 from the workspace security audit[cite: 30]. It completely overhauls the game logic to make rounds server-authoritative, prevents unauthorized on-chain reward minting, introduces proper rate-limiting for gas-spending endpoints, and hardens the random number generation logic against state recovery attacks.

### Key Changes & Remediations

#### 1. Server-Authoritative Reward Minting (F-03)
* **Closing the Minting Oracle:** The `/api/win` endpoint previously accepted unsigned, unverified win claims directly from the client request body and minted rewards unconditionally[cite: 30]. This has been refactored to rely on a server-side Redis validation flow.
* **Secure State Initialization:** A new route, `/api/game/start`, securely selects the winning card using `crypto.randomInt` and stores it in Redis under an unguessable 128-bit `gameId`[cite: 30]. The winning card is deliberately excluded from the client response[cite: 30].
* **Atomic Single-Use Gate:** The `claimRound` logic uses a `SET NX EX` atomic lock to prevent concurrent replay race conditions, ensuring a round can only ever be consumed once[cite: 30].

#### 2. Rate Limiting for Gas & Signer Endpoints (F-11)
* **Sliding-Window Implementation:** A new in-memory rate limiter (`lib/rate-limit.ts`) has been introduced to protect the application's budget[cite: 30]. The game start endpoint is capped at 20 requests/min, while the payout endpoint is restricted to 10 requests/min.
* **Safe Cache Pruning:** The rate-limit cache pruning defers deletions to avoid ES5 `TS2802` `Map` iteration mutation errors[cite: 30].

#### 3. Cryptographically Secure Randomness (F-12)
* **CSPRNG Implementation:** Replaced the vulnerable `Math.random()` (which relies on `xorshift128+` and is susceptible to state recovery and modulo bias) with `crypto.getRandomValues()` paired with explicit rejection sampling (`lib/shuffle.ts`)[cite: 30].

#### 4. Error Masking (F-13)
* **Information Leakage Prevented:** The `app/api/win/route.ts` previously returned raw `error.message` strings from CDP and RPC internals back to the caller[cite: 30]. All upstream errors are now logged strictly server-side and resolved to the client via generic `502 Bad Gateway` or `400 Bad Request` responses[cite: 30].
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