Skip to content

Commit 69d9088

Browse files
steilerDevFrank Steilerclaude
authored
fix(server): resilient rate-limit key + narrower trustProxy for reverse-proxy setups (#1303)
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: Frank Steiler <frank@steiler.de> Co-authored-by: Claude backend-developer (Haiku 4.5) <noreply@anthropic.com>
1 parent 74c7191 commit 69d9088

3 files changed

Lines changed: 15 additions & 2 deletions

File tree

server/src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export async function buildApp(): Promise<FastifyInstance> {
6565
logger: {
6666
level: process.env.LOG_LEVEL || 'info',
6767
},
68-
trustProxy: process.env.TRUST_PROXY === 'true',
68+
trustProxy: process.env.TRUST_PROXY === 'true' ? 1 : false,
6969
});
7070

7171
// Add custom HTTP methods for WebDAV (CalDAV/CardDAV)

server/src/plugins/rateLimitPlugin.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@ export default fp(
88
global: false,
99
max: 200,
1010
timeWindow: '1 minute',
11+
keyGenerator: (request) => {
12+
const ip = request.ip;
13+
if (ip) return ip;
14+
const fwdFor = request.headers['x-forwarded-for'];
15+
if (fwdFor) {
16+
// X-Forwarded-For may be comma-separated; use the first (client) IP
17+
const first = Array.isArray(fwdFor) ? fwdFor[0] : fwdFor.split(',')[0]?.trim();
18+
if (first) return first;
19+
}
20+
const realIp = request.headers['x-real-ip'];
21+
if (typeof realIp === 'string' && realIp.length > 0) return realIp;
22+
return 'unknown';
23+
},
1124
errorResponseBuilder: (_request, context) =>
1225
new AppError(
1326
'RATE_LIMIT_EXCEEDED',

wiki

Submodule wiki updated from e31af42 to d372bdd

0 commit comments

Comments
 (0)