From 455f8cc26e37dc84072537b9193b7f8a6eb355c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Komendarczuk?= Date: Tue, 8 Sep 2026 09:13:04 +0200 Subject: [PATCH] fix: restore per-client rate limiting after fastify trustProxy hardening The fastify/@fastify/proxy-addr bump from the audit fixes made numeric trustProxy values fail closed at runtime (hop-count trust can't verify the immediate peer) and dropped number from the TrustProxy type, which broke the api build and made rate-limit.test.ts collapse all clients behind a proxy into one bucket. Map TRUST_PROXY= to the loopback address explicitly, matching the only documented deployment (reverse proxy on the same host forwarding to 127.0.0.1). --- apps/api/src/config/proxy.ts | 8 +++++++- apps/api/test/rate-limit.test.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/api/src/config/proxy.ts b/apps/api/src/config/proxy.ts index c520b50..ef6f086 100644 --- a/apps/api/src/config/proxy.ts +++ b/apps/api/src/config/proxy.ts @@ -6,7 +6,13 @@ export function resolveTrustProxy(raw = process.env['TRUST_PROXY']): TrustProxy const value = raw?.trim() if (!value || value.toLowerCase() === 'false') return false if (value.toLowerCase() === 'true') return true - if (/^\d+$/.test(value)) return Number(value) + if (/^\d+$/.test(value)) { + // Hop-count-only trust can't validate the immediate peer, so @fastify/proxy-addr + // no longer supports it (it always fails closed). The only documented deployment + // puts the reverse proxy on the same host, forwarding to loopback, so treat a + // numeric value as "trust the loopback interface" to keep TRUST_PROXY=1 working. + return ['127.0.0.1', '::1'] + } const addresses = value.split(',').map((address) => address.trim()).filter(Boolean) if (addresses.length === 0) return false return addresses.length === 1 ? addresses[0]! : addresses diff --git a/apps/api/test/rate-limit.test.ts b/apps/api/test/rate-limit.test.ts index dde0dd6..f300762 100644 --- a/apps/api/test/rate-limit.test.ts +++ b/apps/api/test/rate-limit.test.ts @@ -35,7 +35,7 @@ describe('rate limit isolation and proxy handling', () => { it('parses explicit trust proxy settings safely', () => { assert.equal(resolveTrustProxy(''), false) assert.equal(resolveTrustProxy('false'), false) - assert.equal(resolveTrustProxy('1'), 1) + assert.deepEqual(resolveTrustProxy('1'), ['127.0.0.1', '::1']) assert.deepEqual(resolveTrustProxy('127.0.0.1, ::1'), ['127.0.0.1', '::1']) })