Repository navigation
fix(web): rate-limit inspect and lookup and cache their results - #1322
Conversation
#1307. /api/v1/rate/inspect and /lookup ran several database reads per distinct query with no rate limit, and their result was cached for one request only. - both routes share a per-IP limit of 30 per minute per instance (429 with Retry-After); a durable shared limit is #1247; - the inspection result is cached in the Data Cache for 2 minutes per normalized query (hashed key), also for the inspect page; - the client key prefers the platform-set x-vercel-forwarded-for over a client-supplied forwarded chain (also for the extension routes). Closes #1307 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ache entries Codex round 1 on #1307: - x-vercel-forwarded-for is read only when VERCEL=1; elsewhere it is client input and the forwarded chain is used as before; - an inspection result over 1.5 MB (Next skips entries over 2 MB) is cached as a marker and read uncached, instead of a failed write. Refs #1307 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 43 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Closes #1307
From the apps/web security review. Severity: medium (database load from anonymous callers).
What
/api/v1/rate/inspectand/api/v1/rate/lookupshare a per-client-IP limit of 30 per minute per instance (inspectRateLimiterinserver/rate/api-handler.ts). Past it they answer 429 withRetry-After: 60. A durable shared limit is proposal(db): global per-network limit for extension ingest (m2) #1247.getCachedInspectProductOrShopUrl, also used by the inspect page) is cached for 2 minutes per normalized query. The key is a sha256 of the sanitized query. A result over 1.5 MB (Next skips entries over 2 MB) is cached as a marker and read uncached.extractClientRateLimitKeyprefers the platform-setx-vercel-forwarded-for, but only whenVERCEL=1(Vercel sets it at build and run time). Elsewhere that header is client input and is ignored. The forwarded chain is used as before. This also applies to the extension lookup and ingest limiters.Behaviour change
Inspection results can be up to 2 minutes old; they were fresh per request before.
Tests
spec-scope.test.ts: 30 requests across inspect and lookup pass, the 31st gets 429 withRetry-After, and another client is not limited.core-rate-architecture.test.ts: the Vercel header wins only withVERCEL=1.Review gate
Codex adversarial, 2 rounds (cap 2-3):
Checks
Web
pnpm test,tsc --noEmit, eslint, prettier: green locally.🤖 Generated with Claude Code
📌 TL;DR
This PR implements per-IP rate limiting for the
/inspectand/lookupAPI routes to prevent abuse, and introduces a 2-minute Data Cache layer for inspection queries to reduce redundant database reads.🎯 Type of Change
🔍 Changes Walkthrough
apps/web/src/app/api/v1/rate/__tests__/spec-scope.test.tstestInspectRateLimitto verify that/inspectand/lookupshare a per-IP limit (30 req/min) and correctly return 429 withRetry-Afterheaders.apps/web/src/app/api/v1/rate/inspect/route.tsinspectRateLimiterinto theGEThandler to enforce rate limits before processing requests.apps/web/src/app/api/v1/rate/lookup/route.tsinspectRateLimiterinto theGEThandler to enforce rate limits before processing requests.apps/web/src/server/rate/__tests__/core-rate-architecture.test.tsextractClientRateLimitKeyto verify thatx-vercel-forwarded-fortakes precedence overx-forwarded-forwhen theVERCELenvironment variable is set.apps/web/src/server/rate/api-handler.tsextractClientRateLimitKeyto prioritizex-vercel-forwarded-foron Vercel deployments.2. Defines
inspectRateLimiter(sliding window, 30 req/60s).3. Adds
inspectRateLimitResponsehelper to generate standard 429 JSON responses.apps/web/src/server/rate/index.tsgetCachedInspectProductOrShopUrlto use a SHA-256 hashed key for the Data Cache. Adds logic to handle results exceeding 1.5MB by bypassing the cache (returning uncached data) to avoid Next.js entry size limits.📊 Architectural Flow
sequenceDiagram participant Client participant API as /inspect or /lookup participant Limiter as inspectRateLimiter participant Cache as Data Cache participant DB as Database Client->>API: GET Request (with IP headers) API->>Limiter: Check Rate Limit (extractClientRateLimitKey) alt Rate Limit Exceeded Limiter-->>API: Deny API-->>Client: 429 Too Many Requests (Retry-After: 60) else Rate Limit Allowed Limiter-->>API: Allow API->>Cache: Check Cache (SHA-256 hash of query) alt Cache Hit Cache-->>API: Cached Result else Cache Miss API->>DB: Query Database DB-->>API: Raw Result API->>Cache: Store Result (if < 1.5MB) end API-->>Client: 200 OK (JSON Result) end