From 19e125d814b157d9fbafa3a56cc13982b47f9366 Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Wed, 2 Sep 2026 09:36:45 +0200 Subject: [PATCH] fix(security): raise the general limiter's fallback budget to 300 The general /api limiter had been inert since it was written, so its 100 requests per 15 minutes per IP was never exercised against real traffic. Applying it for the first time with that budget would have 429'd a venue wifi NAT after roughly twenty guests per window, since every call a gallery landing page makes before the password is typed counts. 300 keeps the protection and clears the realistic case. An explicit app_settings value still wins over this fallback. --- backend/src/services/rateLimitService.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/backend/src/services/rateLimitService.js b/backend/src/services/rateLimitService.js index 8e55ff29..fca22c5d 100644 --- a/backend/src/services/rateLimitService.js +++ b/backend/src/services/rateLimitService.js @@ -30,11 +30,20 @@ async function getRateLimitSettings() { 'rate_limit_public_endpoints_only' ]); - // Parse settings into object + // Parse settings into object. + // + // maxRequests: 300 per 15-minute window, per IP, counting only requests + // that carry no admin/gallery token (skipAuthenticated). The general + // limiter was inert from the day it was written (see apiRateLimitGate), + // so its original 100 had never been exercised against real traffic. A + // gallery landing page makes a handful of unauthenticated calls before + // the password is typed; at 100, a venue wifi NAT reached 429 after + // roughly twenty guests per window. An explicit app_settings value still + // wins over this fallback. const config = { enabled: true, windowMinutes: 15, - maxRequests: 100, + maxRequests: 300, authMaxRequests: 5, skipAuthenticated: true, publicEndpointsOnly: false @@ -75,7 +84,7 @@ async function getRateLimitSettings() { return { enabled: true, windowMinutes: 15, - maxRequests: 100, + maxRequests: 300, authMaxRequests: 5, skipAuthenticated: true, publicEndpointsOnly: false