Skip to content

fix(web): rate-limit inspect and lookup and cache their results - #1322

Merged
JOY (JOY) merged 2 commits into
devfrom
fix/1307-inspect-lookup-limits
Oct 29, 2026
Merged

JOY (JOY) merged 2 commits into
devfrom
fix/1307-inspect-lookup-limits

Conversation

@JOY

@JOY JOY (JOY) commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1307

From the apps/web security review. Severity: medium (database load from anonymous callers).

What

  • Rate limit: /api/v1/rate/inspect and /api/v1/rate/lookup share a per-client-IP limit of 30 per minute per instance (inspectRateLimiter in server/rate/api-handler.ts). Past it they answer 429 with Retry-After: 60. A durable shared limit is proposal(db): global per-network limit for extension ingest (m2) #1247.
  • Data Cache: the inspection result (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.
  • Client key: extractClientRateLimitKey prefers the platform-set x-vercel-forwarded-for, but only when VERCEL=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 with Retry-After, and another client is not limited.
  • core-rate-architecture.test.ts: the Vercel header wins only with VERCEL=1.

Review gate

Codex adversarial, 2 rounds (cap 2-3):

  • Round 1 found the Vercel header trusted off Vercel and oversized results that could not be cached. Both fixed in 3093957.
  • Round 2 found no new issue.

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 /inspect and /lookup API routes to prevent abuse, and introduces a 2-minute Data Cache layer for inspection queries to reduce redundant database reads.

🎯 Type of Change

  • 🚀 New feature
  • 🐛 Bugfix
  • 🧹 Refactor
  • ⚡ Performance
  • 📚 Documentation
  • ⚙️ CI / Configuration

🔍 Changes Walkthrough

File Summary of Changes
apps/web/src/app/api/v1/rate/__tests__/spec-scope.test.ts Adds testInspectRateLimit to verify that /inspect and /lookup share a per-IP limit (30 req/min) and correctly return 429 with Retry-After headers.
apps/web/src/app/api/v1/rate/inspect/route.ts Integrates inspectRateLimiter into the GET handler to enforce rate limits before processing requests.
apps/web/src/app/api/v1/rate/lookup/route.ts Integrates inspectRateLimiter into the GET handler to enforce rate limits before processing requests.
apps/web/src/server/rate/__tests__/core-rate-architecture.test.ts Updates tests for extractClientRateLimitKey to verify that x-vercel-forwarded-for takes precedence over x-forwarded-for when the VERCEL environment variable is set.
apps/web/src/server/rate/api-handler.ts 1. Updates extractClientRateLimitKey to prioritize x-vercel-forwarded-for on Vercel deployments.
2. Defines inspectRateLimiter (sliding window, 30 req/60s).
3. Adds inspectRateLimitResponse helper to generate standard 429 JSON responses.
apps/web/src/server/rate/index.ts Refactors getCachedInspectProductOrShopUrl to 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
Loading

JOY (JOY) and others added 2 commits October 29, 2026 02:44
#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>
@vercel

vercel Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
rate Ready Ready Preview Oct 28, 2026 7:52pm UTC

Request Review

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization has no extra usage available to pay for this review.

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.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You'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.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f3081c42-240f-49ed-bb09-b350bede629e
Commits

Reviewing files that changed from the base of the PR and between db049c4 and 3093957.

Files selected for processing: 6
  • apps/web/src/app/api/v1/rate/__tests__/spec-scope.test.ts
  • apps/web/src/app/api/v1/rate/inspect/route.ts
  • apps/web/src/app/api/v1/rate/lookup/route.ts
  • apps/web/src/server/rate/__tests__/core-rate-architecture.test.ts
  • apps/web/src/server/rate/api-handler.ts
  • apps/web/src/server/rate/index.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

dos[bot]
dos Bot approved these changes Oct 28, 2026

@dos dos Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⏱️ Code Review completed (6 eligible files · 8,626 chars · 2 model call(s) · 1 PR unit(s))

Whole diff with bounded context at base 4eca23d / head 3093957.

✅ CLEAN_PASS: Complete diff reviewed

Context investigation was bounded to the explicitly requested snapshot paths.

This branch was successfully deployed

1 active deployment
Preview — 3093957f Deployed Oct 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:frontend Frontend / Next.js / UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(web): inspect and lookup run uncached database reads with no rate limit

1 participant