AOSSIE-Org / AOSSIE-Org/DebateAI

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

Open
#404 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
84
Forks
198
Avg merge
2d 19h
Merged PRs (30d)
30

Description

### 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.:
```bash
for i in {1..30}; do
curl -X POST https:///api/debate-vs-bot \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{"message": "test"}' &
done
```
3. 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.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at the /debate-vs-bot route and other endpoints that proxy Gemini calls, then inspect backend/config/config.prod.yml and the authentication flow. Reproduce the current behavior with the curl sequence in the issue and identify each LLM-calling entry point. Done means over-limit requests receive 429, Retry-After, and a clear JSON body, limits are configurable, and blocked requests do not reach Gemini.

Written by the indexing model from the issue text.

Assessment

Tech stack
express, google-cloud, typescript
Domain
api, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.