Skip to content

fix(server): resilient rate-limit key + narrower trustProxy for reverse-proxy setups#1303

Merged
steilerDev merged 1 commit intobetafrom
fix/proxy-rate-limit-null-ip
Apr 19, 2026
Merged

fix(server): resilient rate-limit key + narrower trustProxy for reverse-proxy setups#1303
steilerDev merged 1 commit intobetafrom
fix/proxy-rate-limit-null-ip

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

Summary

Two production fixes triggered by the fastify 5.8.5 security patch for CVE-2026-33806 (trustProxy socketAddr null-check). Under the tightened code path, request.ip can resolve to undefined when the raw TCP socket lacks metadata — collapsing @fastify/rate-limit's default keyGenerator (which uses request.ip) to a single undefined bucket shared across all unknown-IP callers. This triggers the login max: 20 bucket after 20 requests and returns 429s to all subsequent callers.

Changes:

  • rateLimitPlugin.ts: add explicit keyGenerator with fallback chain request.ip → first x-forwarded-forx-real-ip"unknown". Unknown-IP requests are still rate-limited (bucketed as "unknown") rather than silently shared.
  • app.ts: pass trustProxy: 1 (number of hops) instead of boolean true. We sit behind exactly one reverse proxy in production; the number-based code path was explicitly hardened in 5.8.5.

Public /api/config still exposes trustProxy as boolean — external contract unchanged.

Unblocks PR #1215 (beta → main promotion) E2E Gates.

Test plan

…se-proxy setups

Two production fixes triggered by the fastify 5.8.5 security patch for
CVE-2026-33806 (trustProxy socketAddr null-check). Under the tightened
code path, `request.ip` can resolve to `undefined` when the raw TCP
socket lacks metadata, which collapses `@fastify/rate-limit`'s default
`keyGenerator` (which uses `request.ip`) to a single `undefined`
bucket — effectively shared across all unknown-IP callers.

Changes:
- `server/src/plugins/rateLimitPlugin.ts`: add explicit keyGenerator
  that falls back through `request.ip` → first x-forwarded-for →
  x-real-ip → literal "unknown". Unknown-IP requests are still
  rate-limited (bucketed as "unknown") rather than silently shared.
- `server/src/app.ts`: pass `trustProxy: 1` (number of hops) instead
  of boolean `true`. We sit behind exactly one reverse proxy in
  production; the number-based path is the more precise and robust
  semantic, and it's the code path explicitly restored/hardened in
  5.8.5 per the CVE advisory.

Public `/api/config` still exposes `trustProxy` as boolean — the
external contract is unchanged. Only the Fastify constructor arg is
narrowed.

Unblocks PR #1215 (beta → main promotion) E2E Gates by fixing the
`proxy-setup.spec.ts:186` X-Forwarded-For regression.

Co-Authored-By: Claude backend-developer (Haiku 4.5) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your submission! We require all contributors to sign our Contributor License Agreement before we can accept your contribution.

To sign, please comment on this PR with:
I have read the CLA Document and I hereby sign the CLA


I have read the CLA Document and I hereby sign the CLA


Frank Steiler seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@steilerDev steilerDev merged commit 69d9088 into beta Apr 19, 2026
28 of 32 checks passed
@steilerDev steilerDev deleted the fix/proxy-rate-limit-null-ip branch April 19, 2026 15:56
@github-actions github-actions bot locked and limited conversation to collaborators Apr 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant