Skip to content

fix: replace in-memory rate limit with on-chain + cache hybrid (#223)#231

Closed
GBOYEE wants to merge 2 commits into
Neko-Protocol:devfrom
GBOYEE:fix/faucet-rate-limit-223
Closed

fix: replace in-memory rate limit with on-chain + cache hybrid (#223)#231
GBOYEE wants to merge 2 commits into
Neko-Protocol:devfrom
GBOYEE:fix/faucet-rate-limit-223

Conversation

@GBOYEE

@GBOYEE GBOYEE commented Jun 20, 2026

Copy link
Copy Markdown

Summary

Fixes the faucet rate limit bypass vulnerability where the in-memory Map was per-instance in serverless deployments, allowing cooldown bypass via cold starts or concurrent requests hitting different instances.

Changes

  • Replaced rateLimitMap (module-level Map) with rateLimitCache + on-chain check
  • New checkRateLimit() function uses a two-tier approach:
    1. Fast path: in-memory cache (works for single-instance deployments)
    2. Slow path: queries Stellar RPC for recent transactions from the requesting address (authoritative for serverless/multi-instance)
  • On-chain check is fail-open (allows through if RPC check fails) to maintain faucet availability
  • Moved RPC server creation before rate limit check so the on-chain query can execute

Security Impact

  • Before: Any user could bypass the cooldown by sending concurrent requests or waiting for a cold start
  • After: Rate limit is enforced even across multiple serverless instances by checking on-chain transaction history

Testing

  • The on-chain check gracefully degrades if the RPC is unavailable (fail-open)
  • Existing behavior preserved for single-instance deployments (fast path)

Closes #223

…Protocol#223)

The faucet rate limit used a module-level Map which is per-instance
in serverless deployments (Vercel, Cloudflare Workers, AWS Lambda).
This allowed bypassing the cooldown via cold starts or concurrent
requests hitting different instances.

Fix: checkRateLimit() now uses a two-tier approach:
1. Fast path: in-memory cache (works for single-instance)
2. Slow path: on-chain transaction history check (authoritative
   for serverless/multi-instance deployments)

The on-chain check queries the Stellar RPC for recent transactions
from the requesting address and rejects if any are within the
cooldown window. This is fail-open (allows through if the RPC check
fails) to maintain faucet availability.

Closes Neko-Protocol#223
@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the Oppia Software Labs Team on Vercel.

A member of the Team first needs to authorize it.

@GBOYEE GBOYEE closed this Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: Faucet rate limit uses in-memory Map — bypassable in serverless deploys

1 participant