|
10 | 10 |
|
11 | 11 | | Severity | Count | Status | |
12 | 12 | |----------|-------|--------| |
13 | | -| CRITICAL | 1 | ✅ Fixed | |
14 | | -| HIGH | 2 | ✅ Fixed | |
15 | | -| MEDIUM | 3 | Acknowledged | |
16 | | -| LOW | 2 | Acknowledged | |
| 13 | +| CRITICAL | 2 | ✅ Fixed | |
| 14 | +| HIGH | 4 | ✅ Fixed | |
| 15 | +| MEDIUM | 5 | 3 Acknowledged, 2 Fixed | |
| 16 | +| LOW | 3 | Acknowledged | |
17 | 17 |
|
18 | 18 | --- |
19 | 19 |
|
|
25 | 25 | **Status:** ✅ Fixed |
26 | 26 | **Fix:** Removed hardcoded fallback; now requires `ARC_SETTLER_PRIVATE_KEY` env var. |
27 | 27 |
|
| 28 | +### C-2: Open Redirect in Disconnect Route |
| 29 | + |
| 30 | +**File:** `src/app/api/disconnect/route.ts` |
| 31 | +**Issue:** User-controlled `next` query param passed directly to `new URL()` without validation. |
| 32 | +**Status:** ✅ Fixed — validated to only allow relative paths starting with `/`. |
| 33 | + |
28 | 34 | --- |
29 | 35 |
|
30 | 36 | ## HIGH |
|
38 | 44 | ### H-2: API Disconnect Route Missing Auth Check |
39 | 45 |
|
40 | 46 | **File:** `src/app/api/disconnect/route.ts` |
41 | | -**Issue:** Any unauthenticated request could force-disconnect a user's wallet by calling `GET /api/disconnect`. |
| 47 | +**Issue:** Any unauthenticated request could force-disconnect a user's wallet. |
42 | 48 | **Status:** ✅ Fixed — now requires valid session. |
43 | 49 |
|
| 50 | +### H-3: No Replay Protection for Off-Chain Payments |
| 51 | + |
| 52 | +**File:** `src/lib/x402Server.ts` |
| 53 | +**Issue:** When `settleOnChain: false`, the same payment header could be replayed unlimited times. |
| 54 | +**Status:** ✅ Fixed — added in-memory nonce dedup with 5min TTL. |
| 55 | +**Note:** Ineffective in serverless (Vercel) where each invocation gets a fresh Map. Acceptable for hackathon. |
| 56 | + |
| 57 | +### H-4: Onramp Session Routes Missing Auth Checks |
| 58 | + |
| 59 | +**Files:** `src/app/api/crypto/onramp/session/route.ts`, `src/app/api/crypto/onramp/session/[sessionId]/route.ts` |
| 60 | +**Issue:** Anyone could create Stripe onramp sessions for arbitrary wallets or poll any session ID. |
| 61 | +**Status:** ✅ Fixed — both routes now require authenticated session. |
| 62 | + |
44 | 63 | --- |
45 | 64 |
|
46 | 65 | ## MEDIUM |
47 | 66 |
|
48 | 67 | ### M-1: No Inbound Rate Limiting on API Routes |
49 | 68 |
|
50 | 69 | **Impact:** Unlimited request rates on authenticated endpoints could enable abuse. |
51 | | -**Mitigation:** x402 payment gates on quiz claims (0.001 USDC fee) provide economic rate limiting. Business quota (max 5 API keys/wallet) on key generation. |
| 70 | +**Mitigation:** x402 payment gates on quiz claims (0.001 USDC fee) provide economic rate limiting. |
52 | 71 | **Recommendation:** Add `@upstash/ratelimit` with Redis for production deployment. |
53 | 72 |
|
54 | 73 | ### M-2: Session Table Orphaned Records |
|
62 | 81 | **Issue:** `maskAllInputs: false` records wallet addresses, quiz answers, and auth modal interactions. |
63 | 82 | **Mitigation:** Acceptable for hackathon demo. Set `maskAllInputs: true` before production. |
64 | 83 |
|
| 84 | +### M-4: Error Messages Leak Internal Details |
| 85 | + |
| 86 | +**File:** `src/lib/x402Server.ts` |
| 87 | +**Issue:** Raw error messages from viem (RPC URLs, contract errors) returned to clients. |
| 88 | +**Status:** ✅ Fixed — sanitized to generic messages. |
| 89 | + |
| 90 | +### M-5: Nonce Replay Protection Ineffective in Serverless |
| 91 | + |
| 92 | +**File:** `src/lib/x402Server.ts` |
| 93 | +**Issue:** In-memory Map resets per invocation in Vercel, making nonce dedup ineffective. |
| 94 | +**Mitigation:** Acceptable for hackathon. Use Upstash Redis for production. |
| 95 | + |
65 | 96 | --- |
66 | 97 |
|
67 | 98 | ## LOW |
|
78 | 109 | **Issue:** No explicit `secure`, `httpOnly`, `sameSite` cookie options. Auth.js v5 defaults to `secure: true` in production. |
79 | 110 | **Mitigation:** Verify `NODE_ENV=production` in Vercel environment. |
80 | 111 |
|
| 112 | +### L-3: Fragile `as any` Cast in Session Key Hook |
| 113 | + |
| 114 | +**File:** `src/hooks/useSessionKey.ts:244` |
| 115 | +**Issue:** `signTypedDataAsync(typedData as any)` suppresses TypeScript validation. |
| 116 | +**Mitigation:** Acceptable — wagmi EIP-712 type mismatch workaround. |
| 117 | + |
81 | 118 | --- |
82 | 119 |
|
83 | 120 | ## Recommendations for Production |
84 | 121 |
|
85 | 122 | 1. Add `@upstash/ratelimit` with Redis for API rate limiting |
86 | | -2. Set `maskAllInputs: true` in PostHog config |
87 | | -3. Add a cron job to clean up expired session rows |
88 | | -4. Review `trustHost` setting after deployment |
89 | | -5. Add explicit cookie options to `NextAuth()` config |
| 123 | +2. Use Upstash Redis for nonce replay protection (replaces in-memory Map) |
| 124 | +3. Set `maskAllInputs: true` in PostHog config |
| 125 | +4. Add a cron job to clean up expired session rows |
| 126 | +5. Review `trustHost` setting after deployment |
| 127 | +6. Add explicit cookie options to `NextAuth()` config |
0 commit comments