fix(web): rate-limit expensive endpoints and stop analytics tenant spoofing#1929
Open
richiemcilroy wants to merge 2 commits into
Open
fix(web): rate-limit expensive endpoints and stop analytics tenant spoofing#1929richiemcilroy wants to merge 2 commits into
richiemcilroy wants to merge 2 commits into
Conversation
|
Paragon Review Skipped Hi @richiemcilroy! Your Polarity credit balance is insufficient to complete this review. Please visit https://app.paragon.run to finish your review. |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Member
Author
|
@greptileai please review the PR |
Member
Author
|
@greptileai please review the PR |
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.
Rate-limits the unauthenticated Loom download, messenger, analytics tracking, guest-checkout and desktop-log endpoints, and derives the analytics tenant from the video record instead of trusting client-supplied ids.
Greptile Summary
This PR hardens five unauthenticated or lightly-authenticated endpoints by adding Vercel Firewall-backed rate limiting through a new shared
isRateLimitedhelper, and fixes a tenant-spoofing path in the analytics tracking route by derivingtenantIdfrom the DB-fetched video record instead of trusting client-suppliedbody.orgId/body.ownerId.apps/web/lib/rate-limit.ts: New helper that wraps@vercel/firewall'scheckRateLimit, fails open on any error, is a no-op outside production, and accepts an optional per-user key or explicit headers (needed for Hono handlers wherenext/headersis unavailable).apps/web/app/api/analytics/track/route.ts: Tenant derivation now readsorgIdandownerIdexclusively from the looked-upvideosrow, eliminating the spoofing vector; rate limit guard added before the Tinybird ingest path.apps/web/actions/messenger.ts: Rate limit guard correctly placed before themessengerMessagesinsert and conversation timestamp update, addressing the DB-spam concern raised in the previous review.Confidence Score: 5/5
Safe to merge — all five endpoints are guarded correctly, the tenant-spoofing fix is sound, and the previously raised messenger DB-write ordering issue is resolved.
The rate-limit helper fails open so it cannot break self-hosted or development deployments. The analytics tenant fix removes client trust entirely for existing videos. The messenger guard is now placed before any database writes. No new defects were introduced in the changed paths.
No files require special attention beyond the pre-existing isRateLimited name shadowing inside importFromLoom in apps/web/actions/loom.ts, which was flagged in a previous review pass.
Important Files Changed
Comments Outside Diff (2)
apps/web/actions/messenger.ts, line 180-226 (link)The user message is inserted into
messengerMessages(line 180) andmessengerConversationsis updated (line 192) beforeisRateLimitedis evaluated at line 221. When a request is rejected by the rate limiter, the message already lives in the database without a corresponding AI reply. On the user's next (successful) retry the orphaned message is still in the history, so the AI receives the same user turn twice with no assistant turn between them, corrupting the conversation state.Prompt To Fix With AI
apps/web/actions/loom.ts, line 451-457 (link)isRateLimitedshadowed by local variableThe new top-level import
import { isRateLimited, RATE_LIMIT_IDS } from "@/lib/rate-limit"is shadowed insideimportFromLoombyconst isRateLimited = await createLoomImportRateLimitCheck(user.id). The local binding wins within that function scope, so there is no runtime breakage today, but the identical names make the code misleading — a future reader may confuse the two, or a linter may flag it as a shadowing error. Consider renaming the local variable (e.g.loomImportRateLimitCheck) to avoid the collision.Prompt To Fix With AI
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Reviews (3): Last reviewed commit: "fix(web): rate-limit messenger before pe..." | Re-trigger Greptile