Skip to content

[BUG]: No rate limiting on AI debate endpoints — allows abuse of Gemini/LLM API quota #404

Description

@Mansi2007275

Bug Description

The backend exposes AI-powered debate endpoints — primarily /debate-vs-bot and any other routes that proxy requests to the Gemini LLM API (e.g. AI opponent response generation, fallacy detection, or post-debate analysis endpoints) — without any request throttling in front of them.

Each hit to these endpoints triggers at least one outbound call to the Gemini API, which is billed and quota-limited by Google. Since there is currently no middleware enforcing per-user, per-session, or per-IP request limits, the endpoint's effective rate is bounded only by network/browser speed — meaning a single client can fire dozens or hundreds of requests per minute with a simple script or load-testing tool.

This creates two concrete risks:

1. Cost/Quota exhaustion (availability risk):
The Gemini API key configured in backend/config/config.prod.yml is shared across all users of the deployed instance. A single abusive client can exhaust the daily/per-minute quota, which would cause the LLM to stop responding for every other user on the platform — not just the abuser. This turns a single bad actor into a platform-wide outage.

2. Unbounded billing exposure (cost risk):
Since Gemini API usage is metered, an attacker (or even an accidental infinite-loop bug in the frontend) could generate significant unexpected cost with no circuit breaker in place to stop it.

Why this is more than a "nice to have":
Unlike a generic REST endpoint, LLM-backed endpoints are inherently expensive per-call (both in latency and $), which is exactly the class of endpoint that should have stricter throttling than the rest of the API — but currently there's no differentiation; all routes appear to be treated the same, if any rate limiting exists at all.

Steps to Reproduce

  1. Authenticate as any valid user and obtain a session/auth token
  2. Using curl, Postman, or a small script, send 20–30 requests in rapid succession to the debate-vs-bot endpoint (or whichever route triggers an LLM call), e.g.:
   for i in {1..30}; do
     curl -X POST https://<backend-host>/api/debate-vs-bot \
       -H "Authorization: Bearer <token>" \
       -H "Content-Type: application/json" \
       -d '{"message": "test"}' &
   done
  1. Observe that all (or nearly all) requests return 200 OK and are forwarded to Gemini, with no 429 responses or delay introduced by the server

Expected Behavior

  • LLM-backed routes should have a dedicated rate-limiting middleware, separate from (and stricter than) general API routes
  • Limiting should be scoped per authenticated user (not just per-IP, since users may share IPs on mobile networks/NAT)
  • Requests over the limit should receive a 429 Too Many Requests with a Retry-After header and a clear JSON error body
  • Limits should be configurable via environment variables (e.g. LLM_RATE_LIMIT_MAX, LLM_RATE_LIMIT_WINDOW_MS) rather than hardcoded, so different deployments can tune based on their quota tier

Impact

High — this is a direct, low-effort path to:

  • Full-platform LLM feature outage for all users (shared quota exhaustion)
  • Uncontrolled billing cost on the project maintainers' Gemini API key
  • No audit trail currently exists to identify which user/IP caused the exhaustion, making incident response harder

Suggested Fix (high level)

Introduce an express-rate-limit (or equivalent) middleware scoped specifically to LLM-calling routes, keyed by authenticated user ID where available, falling back to IP. This should sit before the controller that calls the Gemini API, so blocked requests never reach the LLM call itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions