Skip to content

Add rate-limiting to /admin/ingest #17

@GavT

Description

@GavT

Summary

/admin/ingest (added in #13) is the push-mode endpoint for the laptop ingester. It is currently protected only by a constant-time X-Ingest-Token header check and a body-size guard. There is no rate limit, so an attacker who guesses or steals the token (or sends unauthenticated requests) can hammer the endpoint freely.

The endpoint is mounted on the live backend even in pull mode, so this is reachable on the public internet today via http://api.fueller.app/admin/ingest and http://52.30.72.127/admin/ingest.

Why it matters

  • CPU / memory amplification. A 32 MiB ingest payload (default ingest.maxBodyBytes) is JSON-parsed and built into Maps before the cache swap. An attacker doesn't need to know the token to make the server burn CPU on parsing; they just need to send a malformed-but-large body.
  • 401 brute-force. No rate limit means a token-guessing loop is essentially free.
  • Log noise. Every rejected request gets logged; an attacker can fill disks.

Proposed change

Add a token-bucket rate limiter to the /admin/ingest route specifically. Reasonable defaults:

  • 10 requests per minute per source IP for unauthenticated/401 responses
  • 60 requests per hour per source IP for authenticated 200/4xx responses (legitimate ingesters fire every 30 min, so 60/hr leaves generous headroom)
  • Respond with HTTP 429 and a Retry-After header when exceeded

Ktor has a RateLimit plugin that handles this; can be scoped to a single route so /api/search is unaffected.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    securitySecurity finding

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions