abhigyanpatwari/GitNexus · warning

[gitnexus serve] Bound to ${boundHost} with ${TRUST_PROXY_EN

Error message

[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.

What it means

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.

Source

Thrown at gitnexus/src/server/middleware.ts:382

 * {@link resolveTrustProxy} cannot detect this — it sees the env value and not
 * what the server bound. A non-loopback bind is the shape of a deployment behind
 * a load balancer, and {@link DEFAULT_TRUST_PROXY} matches only loopback and the
 * private ranges, so a cloud LB outside them is never trusted: `req.ip` is the
 * LB on every request and the per-IP limit silently becomes one global limit.
 *
 * Silent when {@link TRUST_PROXY_ENV} is set — including to a value that then
 * fails validation, which {@link resolveTrustProxy} has already warned about.
 *
 * @param boundHost - `createServer`'s `host`. A wildcard bind warns too: it
 *   accepts traffic on every interface, a load balancer included.
 */
export function warnIfRateLimitKeysCollapse(boundHost?: string): void {
  if (process.env[TRUST_PROXY_ENV]?.trim()) return;
  if (!boundHost) return;
  // normalizeBoundHost returns undefined for a wildcard or unparseable host,
  // neither of which is loopback — so both warn.
  if (isLoopbackHostname(normalizeBoundHost(boundHost))) return;
  logger.warn(
    { host: boundHost, trustProxy: DEFAULT_TRUST_PROXY },
    `[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.`,
  );
}

function rejectTrustProxy(value: string, reason: string): string {
  logger.warn(
    { [TRUST_PROXY_ENV]: value },
    `[gitnexus serve] Ignoring ${TRUST_PROXY_ENV}=${value} (${reason}); falling back to ` +
      `'${DEFAULT_TRUST_PROXY}'.`,
  );
  return DEFAULT_TRUST_PROXY;
}

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Set GITNEXUS_TRUST_PROXY to the number of proxies you control, e.g. GITNEXUS_TRUST_PROXY=1
  2. Confirm your proxy sets X-Forwarded-For correctly, otherwise trusting it accomplishes nothing
  3. If there is truly no proxy in front, the warning is a false alarm: prefer a loopback bind and it stays silent

Example fix

# before
gitnexus serve --host 0.0.0.0        # behind an ALB: req.ip == balancer for everyone

# after
GITNEXUS_TRUST_PROXY=1 gitnexus serve --host 0.0.0.0   # req.ip == real client IP
Defensive patterns

Strategy: validation

Validate before calling

const trustProxy = process.env.GITNEXUS_TRUST_PROXY?.trim();
if (!trustProxy && boundHost && !isLoopbackHostname(boundHost)) {
  // Behind a non-RFC1918 load balancer, per-IP rate limits collapse into
  // one shared bucket — refuse to start until the hop count is set.
  throw new Error('Set GITNEXUS_TRUST_PROXY=<proxy hop count> when serving behind a proxy');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/7d0f369eb9ddccc8. Report an issue: GitHub.