fix: isolate compare route cache per user to prevent cross-user data exposure (GHSA-6c5j-4w43-2v8f #3)#595
Closed
advikdivekar wants to merge 1 commit into
Conversation
…er data exposure
Next.js fetch cache keys by URL only, excluding Authorization headers. With
next: { revalidate }, User A's private repo data fetched with their token was
cached and served to User B querying the same GitHub username within the
one-hour window.
Replace all four next: { revalidate: 3600 } calls with cache: "no-store" and
wrap the full computation in withMetricsCache keyed by
metrics:{githubId}:compare:{username}. Each user gets an isolated cache entry
— no two users can share a response. Gracefully degrades to live fetches when
Redis is unavailable.
|
@advikdivekar is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel. A member of the Team first needs to authorize it. |
GSSoC Label Checklist 🏷️@Priyanshu-byte-coder — please apply the appropriate labels before merging: Difficulty (pick one):
Quality (optional):
Validation (required to score):
|
Contributor
Author
|
Closing — patch will be submitted through the private advisory fork (GHSA-6c5j-4w43-2v8f) to avoid public disclosure before coordinated release. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The
/api/metrics/compareroute usednext: { revalidate: 3600 }on four GitHub API fetch calls. Next.js's built-in fetch cache keys responses by URL only — theAuthorizationheader is not part of the cache key.This meant: if User A (with private repositories) queried a GitHub username, their response was cached under the GitHub API URL. User B querying the same username within the one-hour window received User A's cached response, which could include commit counts and repository metadata from User A's private repositories.
Root cause:
next: { revalidate }is incompatible with per-user authenticated requests. Any user's private data fetched with their token becomes visible to any other user who queries the same target URL.What changed
src/app/api/metrics/compare/route.tsnext: { revalidate: 3600 }options withcache: "no-store"to opt out of the shared URL-keyed fetch cachewithMetricsCache(existing utility from@/lib/metrics-cache) with a cache key ofmetrics:{session.githubId}:compare:{username}githubIdcomponent ensures no two users ever share a cache entryisMetricsCacheBypassedsupport so clients can force a cache refresh with?refresh=1How to verify
?refresh=1query param bypasses the cache and fetches fresh dataRegression check
UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKENare not setFixes GHSA-6c5j-4w43-2v8f vulnerability #3 (High).