DocHub
Two-phase security audit with severity breakdown and remediation status

Security Audit and Fixes

Audit Summary

Two security audits conducted on the Ricoya codebase. Phase 1 (post-migration) covered payment security, auth, input validation, API security, and infrastructure. Phase 2 (March 4, 2026) covered API routes, auth/payments, and client-side vulnerabilities.

Phase 1 — Post-Migration Audit

Severity Found Fixed
Critical 5 5
High 8 6
Medium 9 8
Low 5 3
Total 27 22

Phase 2 — Full Codebase Audit (March 4)

Severity Found Fixed
Critical 4 1
High 9 0
Medium 7 0
Total 20 1

Phase 1 Critical Fixes (All Resolved)

1. Cart Not Cleared on Logout

Previous cart contents persisted in localStorage after logout. Another user on the same device could see or submit the previous user’s cart.

Fix: User-specific localStorage keys (cart_<userId>). Cart data isolated per user.

2. No Ownership Check on Order Retrieval

Any authenticated user could view any order by ID.

Fix: Added ownership validation. Customers can only view their own orders (returns 403 otherwise).

3. US Fallback Address

Default/fallback address data referenced US locations. App operates in Honduras.

Fix: Changed fallback to Honduras (Tegucigalpa, Francisco Morazan, HN). Removed test data from fallbacks.

4. Sandbox Text in UI

6 instances of sandbox/test text visible to users in production.

Fix: Replaced all sandbox references with production-appropriate text.

5. Dev Bypass Route

Development-only login bypass route was accessible in production.

Fix: Gutted route to return hard 403. No bypass logic remains.

6. No Impersonation Audit Logging

Admin impersonation of other users had no audit trail.

Fix: Added logging with admin/target details on every impersonation action.

Phase 1 High Priority Fixes

7. Payment Flow Console Logs

28 console.log statements in payment processing code could expose data.

Fix: All gated behind development environment check.

8. Logout Race Condition

Navigation could fire before signOut completed.

Fix: Reordered to close sidebar, await logout, then navigate to login.

9. Silent Repository Failures

Catch blocks in 16 repositories silently swallowed errors.

Fix: Added error logging to 25+ catch blocks across all repositories.

10. Security Headers

No security headers were set on responses.

Fix: Added X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS, Permissions-Policy in Next.js config.

11. Cart Negative Amounts

No validation preventing negative monetary values in cart calculations.

Fix: Added floor-to-zero guard on all 5 cent fields in cart repository.

Rate Limiting — Deferred

No rate limiting on any endpoint. Deferred pending architectural decision.

Payment Callback Signature — Deferred

Deferred. Mitigated by downstream verification step.

Phase 1 Medium Priority Fixes

  • Rating user_id type — Changed to accept both number and string
  • SWR cache on logout — Mitigated by localStorage cleanup + SWR revalidation on auth change
  • Impersonation not cleared on logout — Added cleanup in AuthContext
  • API timeout message — Protected paths return user-friendly session expired message
  • PayPal restaurantId null — Cart page passes restaurantId as search param on PayPal return URL
  • Middleware route protection — Expanded to protect admin, manager, driver, orders, cart, profile routes
  • Menu error no retry — Added retry button
  • Checkout step revert silent — Added notification explaining why user was reverted

Phase 1 Post-Migration Bug Fixes

  • SQL injection in push notify route — string interpolation replaced with parameterized queries
  • Push notify role check — Added admin role requirement (was open to any authenticated user)
  • Driver claim race condition — Checks if update affected rows (0 = already claimed)
  • Query method fix — Changed .single() to .maybeSingle() across 14 lookup functions in 9 repos
  • SQL injection in driver routes — Replaced string interpolation with safe array queries
  • Restaurant logs — Added missing RLS policies and indexes

Phase 2 Critical Findings (March 4)

C1. Push Notify — No Role Check (FIXED)

/api/push/notify — any authenticated user could send mass push notifications. No admin role verification.

Status: Fixed in Phase 1 post-migration fixes.

C2. Payment Status — Customer Can Mark As Paid

/api/orders/[orderId]/payment-status — customers can mark their own orders as “paid” without actual payment processing.

Status: Open. Needs server-side payment verification before status update.

C3. Discount Code Enumeration — No Auth

/api/cart/validate-discount — no authentication required. Anyone can enumerate valid discount codes.

Status: Open. Add auth requirement.

C4. Payment Amount Not Validated Server-Side

CyberSource 3DS verify and PayPal capture do not validate that the payment amount matches the order total. Client-submitted amount is trusted.

Status: Open. Server must recalculate order total before confirming payment.

Phase 2 High Findings

Issue Route/Component Status
UUID vs numeric ID mismatch (systemic) Driver access checks always fail Open
Mass assignment on restaurant creation owner_user_id accepted from request body Open
Driver/customer PII exposed No field masking on sensitive data Open
No rate limiting on auth endpoints Login, signup, OTP Open
Admin endpoints trust client role No server-side role verification Open
Order total manipulation Client-submitted totals used in payment Open
Missing CSRF protection State-changing POST/PUT/DELETE routes Open
Insecure direct object references Multiple routes lack ownership checks Open
API keys in client bundle Supabase anon key exposed (mitigated by RLS) Accepted risk

Phase 2 Medium Findings

  • RLS requires auth for all SELECT (menus, restaurants, categories) — unauthenticated users see blank pages
  • No input sanitization on user-generated content (names, addresses, notes)
  • Session tokens never explicitly invalidated on password change
  • No account lockout after failed login attempts
  • Push subscription endpoint accepts any user_id
  • File upload accepts any content type (no validation)
  • Error messages leak internal structure (stack traces in dev)