Skip to content

Backend: Queue routes accept POST /queues without authentication — any caller can create, advance, or close any queue #50

Description

@k-deejah

Difficulty: Advanced

Problem

1. POST /api/queues — unauthenticated queue creation
backend/src/routes/queues.tsrouter.post('/') creates a new queue with no authentication check. Any caller with network access to the API can create queues, polluting the queue registry with arbitrary data. The only validation is the Zod schema (name, slug, maxPositions). There is no operator credential, API key, or JWT check.

2. POST /api/queues/:id/advance and POST /api/queues/:id/close — unauthenticated state mutations
These two routes mutate queue lifecycle state (advancing positions, closing queues) with no authentication. An attacker can prematurely close any queue or trigger advancement before the operator intends it. The writeRateLimiter (20 req/min) is applied, but this is not an authentication control.

3. No authentication middleware anywhere in the backend
The entire backend has no authentication layer. backend/src/index.ts applies helmet, cors, rate limiting, and request logging — but no JWT verification, no API key middleware, and no session management. The admin-only routes (advance, close, escrow release/refund) are indistinguishable from participant routes (enroll, lookup) from an auth perspective.

Impact: Any external actor can create queues, advance active queues early, close queues prematurely, and release escrow funds — all without any credential. This is a critical security gap for any production deployment.

Proposed Solution

  • Create backend/src/middleware/auth.ts with an API key authentication middleware: reads X-API-Key header, validates against an OPERATOR_API_KEY environment variable (hashed with bcrypt or compared via crypto.timingSafeEqual).
  • Define two auth tiers: requireAuth (operator only, for create/advance/close/escrow-release) and no auth required (read-only routes, participant enrollment).
  • Apply requireAuth to: POST /api/queues, POST /api/queues/:id/advance, POST /api/queues/:id/close, POST /api/escrow/release, POST /api/escrow/refund.
  • Add OPERATOR_API_KEY to backend/.env.example with a note about hashing.
  • Add auth tests: valid key passes, invalid key returns 401, missing key returns 401, timing-safe comparison (no timing oracle).

Acceptance Criteria

  • backend/src/middleware/auth.ts created with requireAuth middleware
  • requireAuth reads X-API-Key header and validates against OPERATOR_API_KEY env var
  • Comparison uses crypto.timingSafeEqual to prevent timing oracle attacks
  • POST /api/queues (create) requires authentication
  • POST /api/queues/:id/advance requires authentication
  • POST /api/queues/:id/close requires authentication
  • POST /api/escrow/release and POST /api/escrow/refund require authentication
  • Read-only routes and enrollment routes remain unauthenticated
  • Missing or invalid X-API-Key returns { error: { message: "Unauthorized", status: 401 } }
  • OPERATOR_API_KEY documented in backend/.env.example
  • Auth middleware tested for valid key, invalid key, missing key, and timing-safe comparison

Contributor Note

If assigned, your PR must explain the crypto.timingSafeEqual requirement (why naive === comparison is vulnerable to timing attacks), describe how OPERATOR_API_KEY should be generated and stored in production (length, entropy), show the 401 response format, and discuss whether JWT with short expiry is preferable to static API keys for this use case.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions