{"record":{"id":"7d0f369eb9ddccc8","repo":"abhigyanpatwari/GitNexus","slug":"gitnexus-serve-bound-to-boundhost-with-trus","errorCode":null,"errorMessage":"[gitnexus serve] Bound to ${boundHost} with ${TRUST_PROXY_ENV} unset, so 'trust proxy' is '${DEFAULT_TRUST_PROXY}'. A load balancer outside those ranges is not trusted, so req.ip is the balancer on every request and the per-IP rate limit becomes one shared limit across all callers. Set ${TRUST_PROXY_ENV} to the number of proxies you control.","messagePattern":"\\[gitnexus serve\\] Bound to (.+?) with (.+?) unset, so 'trust proxy' is '(.+?)'\\. A load balancer outside those ranges is not trusted, so req\\.ip is the balancer on every request and the per-IP rate limit becomes one shared limit across all callers\\. Set (.+?) to the number of proxies you control\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gitnexus/src/server/middleware.ts","lineNumber":382,"sourceCode":" * {@link resolveTrustProxy} cannot detect this — it sees the env value and not\n * what the server bound. A non-loopback bind is the shape of a deployment behind\n * a load balancer, and {@link DEFAULT_TRUST_PROXY} matches only loopback and the\n * private ranges, so a cloud LB outside them is never trusted: `req.ip` is the\n * LB on every request and the per-IP limit silently becomes one global limit.\n *\n * Silent when {@link TRUST_PROXY_ENV} is set — including to a value that then\n * fails validation, which {@link resolveTrustProxy} has already warned about.\n *\n * @param boundHost - `createServer`'s `host`. A wildcard bind warns too: it\n *   accepts traffic on every interface, a load balancer included.\n */\nexport function warnIfRateLimitKeysCollapse(boundHost?: string): void {\n  if (process.env[TRUST_PROXY_ENV]?.trim()) return;\n  if (!boundHost) return;\n  // normalizeBoundHost returns undefined for a wildcard or unparseable host,\n  // neither of which is loopback — so both warn.\n  if (isLoopbackHostname(normalizeBoundHost(boundHost))) return;\n  logger.warn(\n    { host: boundHost, trustProxy: DEFAULT_TRUST_PROXY },\n    `[gitnexus serve] Bound to ${boundHost} with ${TRUST_PROXY_ENV} unset, so 'trust proxy' is ` +\n      `'${DEFAULT_TRUST_PROXY}'. A load balancer outside those ranges is not trusted, so req.ip ` +\n      `is the balancer on every request and the per-IP rate limit becomes one shared limit across ` +\n      `all callers. Set ${TRUST_PROXY_ENV} to the number of proxies you control.`,\n  );\n}\n\nfunction rejectTrustProxy(value: string, reason: string): string {\n  logger.warn(\n    { [TRUST_PROXY_ENV]: value },\n    `[gitnexus serve] Ignoring ${TRUST_PROXY_ENV}=${value} (${reason}); falling back to ` +\n      `'${DEFAULT_TRUST_PROXY}'.`,\n  );\n  return DEFAULT_TRUST_PROXY;\n}\n","sourceCodeStart":364,"sourceCodeEnd":399,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/middleware.ts#L364-L399","documentation":"warnIfRateLimitKeysCollapse fires when serve binds a non-loopback host and GITNEXUS_TRUST_PROXY is unset. The default 'trust proxy' value ('loopback, linklocal, uniquelocal') does not trust a load balancer outside those ranges, so req.ip resolves to the balancer's address on every request and the per-IP rate limit collapses into one shared limit across all callers — one abusive client can exhaust everyone's quota.","triggerScenarios":"gitnexus serve bound to a non-loopback (or wildcard) host behind a cloud load balancer or reverse proxy outside RFC1918/link-local ranges, with GITNEXUS_TRUST_PROXY unset: every request lands in a single rate-limit bucket keyed on the balancer IP.","commonSituations":"Deploying behind ALB/Cloudflare/nginx on a public subnet; the visible symptom is organization-wide 429 responses triggered by one heavy consumer — the classic Express trust-proxy collapse.","solutions":["Set GITNEXUS_TRUST_PROXY to the number of proxies you control, e.g. GITNEXUS_TRUST_PROXY=1","Confirm your proxy sets X-Forwarded-For correctly, otherwise trusting it accomplishes nothing","If there is truly no proxy in front, the warning is a false alarm: prefer a loopback bind and it stays silent"],"exampleFix":"# before\ngitnexus serve --host 0.0.0.0        # behind an ALB: req.ip == balancer for everyone\n\n# after\nGITNEXUS_TRUST_PROXY=1 gitnexus serve --host 0.0.0.0   # req.ip == real client IP","handlingStrategy":"validation","validationCode":"const trustProxy = process.env.GITNEXUS_TRUST_PROXY?.trim();\nif (!trustProxy && boundHost && !isLoopbackHostname(boundHost)) {\n  // Behind a non-RFC1918 load balancer, per-IP rate limits collapse into\n  // one shared bucket — refuse to start until the hop count is set.\n  throw new Error('Set GITNEXUS_TRUST_PROXY=<proxy hop count> when serving behind a proxy');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set GITNEXUS_TRUST_PROXY to your proxy count in every proxied deployment","Verify your proxy actually sets X-Forwarded-For","Watch for sudden all-user 429s — the signature of collapsed rate-limit keys"],"tags":["rate-limit","trust-proxy","reverse-proxy","configuration","server"],"backgroundTag":"trust-proxy-misconfiguration","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}