Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

7 of 13 RATE_LIMIT_IDS are declared but never called, so those endpoints have no rate limit

オープン
#2,039 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
typescript
領域
api, backend, security

調査の方向性

apps/web/lib/rate-limit.ts から始め、RATE_LIMIT_IDS が宣言の外部でどのように参照されているかを調べます。指定された2つのルート、apps/web/app/api/settings/billing/guest-checkout/route.ts と apps/web/app/api/analytics/track/route.ts を、apps/web/app/api/docs/ask/route.ts と比較します。宣言された ID がそれぞれのエンドポイントから呼び出されるか削除され、未使用の ID を防ぐ回帰テストがあれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Summary

RATE_LIMIT_IDS in apps/web/lib/rate-limit.ts declares 13 rule ids, each with a doc comment naming the abuse it guards and a suggested window. 7 of them are never referenced anywhere in the codebase, so the endpoints they describe run with no rate limit at all.

Counting references outside the declaration file itself:

id referenced endpoint it names
AGENT_TOKEN_EXCHANGE 2 wired
AGENT_AUTHORIZATION 2 wired
AGENT_UNLOCK 1 wired
AGENT_LOOM_IMPORT 2 wired
TRANSLATE_TRANSCRIPT 1 wired
DOCS_ASK 1 wired
AUTH_OTP_VERIFY 0 Email OTP verification (brute-force guard)
AUTH_OTP_SEND 0 Email OTP / magic-link send (mailbomb + token-reseed)
LOOM_DOWNLOAD 0 Unauthed Loom download/convert (ffmpeg + memory DoS)
MESSENGER_MESSAGE 0 Anonymous support chat (Groq + Supermemory cost)
ANALYTICS_TRACK 0 Unauthed view tracking (Tinybird ingest + notifications)
GUEST_CHECKOUT 0 Unauthed guest checkout (Stripe object/cost abuse)
DESKTOP_LOGS 0 Unauthed desktop log to Discord forwarding (spam)
$ grep -rn AUTH_OTP_VERIFY apps packages --include='*.ts' --include='*.tsx' | grep -v lib/rate-limit.ts
(no output)

Same for the other six.

Why this is easy to miss

The file's own comment explains that a rule id with no matching Vercel Firewall dashboard rule fails open:

An ID that has no matching dashboard rule fails OPEN (checkRateLimit returns { rateLimited: false, error: "not-found" }) ... but it also provides no protection until the rule exists.

So there is already one silent-failure mode by design. A declared-but-uncalled id is a second one, and it is invisible from the dashboard side too: someone can create rl_guest_checkout in the Firewall, see it configured, and reasonably assume the endpoint is protected while no code ever calls it.

Two of the unprotected endpoints, checked

apps/web/app/api/settings/billing/guest-checkout/route.ts — no isRateLimited, no getCurrentUser, no auth of any kind. It reads priceId and quantity from the JSON body and calls stripe().checkout.sessions.create(...) directly. Anyone can create unbounded Stripe checkout sessions.

apps/web/app/api/analytics/track/route.ts — no isRateLimited. It uses provideOptionalAuth, so anonymous requests are expected, and it writes to Tinybird and can trigger createAnonymousViewNotification / sendFirstViewEmail. That is the exact combination the comment describes ("Tinybird ingest + notifications").

I checked those two by reading the route files. I did not audit all seven endpoints in the same depth, and I would rather say so than imply a completeness I have not verified.

What "wired" looks like, for reference

apps/web/app/api/docs/ask/route.ts is the model:

if (
  isLocallyRateLimited(ip) ||
  (await isRateLimited(RATE_LIMIT_IDS.DOCS_ASK, { headers: request.headers }))
) {
  return Response.json({ error: "Too many questions right now. Try again in a minute." }, { status: 429 });
}
Expected

Either each declared id is called at the endpoint it names, or the unused ones are removed so the constant does not imply protection that is not there.

Suggested direction

I would rather not blanket-wire seven endpoints in one PR without knowing the intent — some may be deliberately staged ahead of the dashboard rules being created. What I would suggest, and am happy to implement:

  1. A cheap regression guard: a unit test that asserts every key in RATE_LIMIT_IDS is referenced at least once outside the declaration file. That turns "declared but never called" into a CI failure rather than something found by reading.
  2. Then wire the endpoints, either all in one follow-up or one at a time, whichever you prefer to review.

I have (1) ready and will open a PR referencing this issue, since it is the part that holds regardless of what you decide about each endpoint. Tell me which of the seven you want wired and I will follow up.

主要言語
Rust
スター
22.5k
フォーク
1.9k
平均マージ
6時間 33分
マージ済み PR(30日)
77

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

CapSoftware/Cap のほかの issue

CapSoftware/Cap の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。