abhigyanpatwari/GitNexus · critical · Error
Refusing to start eval-server on non-loopback host
Error message
Refusing to start eval-server on non-loopback host ${host} without authentication. Set GITNEXUS_AUTH_TOKEN or bind to 127.0.0.1, localhost, or ::1. What it means
A startup security guard: assertSecureEvalServerBinding refuses to expose the eval-server query surface on a non-loopback host unless a bearer token is configured (GITNEXUS_AUTH_TOKEN from the shell, .env.local, or .env). Loopback hosts (127.0.0.1, localhost, ::1) may run unauthenticated; everything else — 0.0.0.0, LAN IPs, hostnames resolving off-box — must have auth or the process exits.
Solutions
- Set GITNEXUS_AUTH_TOKEN (export in the shell, or put GITNEXUS_AUTH_TOKEN=... in .env.local/.env at the server cwd) and restart
- Or keep it unauthenticated and bind explicitly to a loopback host: --host 127.0.0.1 (in Docker, also publish with 127.0.0.1:PORT:PORT on the host)
- For remote access, prefer an authenticated reverse-proxy/tunnel over widening the bind
- Generate a strong token: openssl rand -hex 32; clients must then send 'Authorization: Bearer <token>'
Example fix
# before $ gitnexus eval-server --host 0.0.0.0 Error: Refusing to start eval-server on non-loopback host 0.0.0.0 without authentication. # after $ export GITNEXUS_AUTH_TOKEN=$(openssl rand -hex 32) $ gitnexus eval-server --host 0.0.0.0
Defensive patterns
Strategy: validation
Validate before calling
import { isIP } from 'node:net';
const LOOPBACK = new Set(['127.0.0.1', 'localhost', '::1']);
function isSafeBind(host: string, token: string | undefined): boolean {
return Boolean(token) || LOOPBACK.has(host);
}
// check BEFORE starting the server
if (!isSafeBind(process.env.HOST ?? '127.0.0.1', process.env.GITNEXUS_AUTH_TOKEN)) {
throw new Error('Refusing unauthenticated non-loopback bind');
} Type guard
const isLoopbackHost = (host: string): boolean => host === '127.0.0.1' || host === 'localhost' || host === '::1';
Try / catch
try {
assertSecureEvalServerBinding(host, token);
} catch (err) {
if (err instanceof Error && err.message.includes('non-loopback')) {
// set GITNEXUS_AUTH_TOKEN or switch --host to 127.0.0.1, then restart
}
} Prevention
- Default to --host 127.0.0.1; widen only when consumers actually need reach
- In Docker, publish as 127.0.0.1:PORT:PORT on the host unless remote access is intended
- Always pair a widened bind with a strong GITNEXUS_AUTH_TOKEN (openssl rand -hex 32)
- Treat the refusal as a control, not a bug — do not work around it by binding loopback proxies without auth
When it happens
Trigger: Starting eval-server with --host 0.0.0.0 or a LAN IP while GITNEXUS_AUTH_TOKEN is unset/whitespace-empty; also binding a hostname that does not resolve to a loopback address.
Common situations: Running the eval server inside Docker with -p port publishing (container binds 0.0.0.0 by default); exposing it on a LAN for another machine to query; CI containers binding all interfaces; production-style deployments reusing the dev tool.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- argument contains a double quote, unsafe for the Windows…
- argument contains NUL/CR/LF, unsafe for the Windows shell
- AZURE_DEVOPS_URL is configured over cleartext http:// — the…
- : HuggingFace download circuit is open after repeated…
- : HuggingFace download circuit opened after consecutive…
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20).
Data as JSON: /api/errors/b1f170fc4c752c30.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/cli/eval-server.ts:155
host: string,
env: NodeJS.ProcessEnv,
cwd: string = process.cwd(),
): { token?: string; warning?: string } {
try {
return { token: resolveEvalServerAuthToken(env, cwd) };
} catch (error) {
if (isEvalServerLoopbackHost(host)) {
const reason = error instanceof Error ? error.message : String(error);
return { warning: `${reason} Continuing without authentication on loopback host ${host}.` };
}
throw error;
}
}
/** Refuse exposure of the eval-server query surface without authentication. */
export function assertSecureEvalServerBinding(host: string, authToken: string | undefined): void {
if (!authToken && !isEvalServerLoopbackHost(host)) {
throw new Error(
`Refusing to start eval-server on non-loopback host ${host} without authentication. ` +
'Set GITNEXUS_AUTH_TOKEN or bind to 127.0.0.1, localhost, or ::1.',
);
}
}
/** Validate the exact Bearer header while keeping token comparison constant-time. */
export function isEvalServerBearerAuthorized(
authorization: string | string[] | undefined,
authToken: string | undefined,
): boolean {
if (!authToken) return true;
const expected = Buffer.from(`Bearer ${authToken}`, 'utf8');
const supplied = typeof authorization === 'string' ? Buffer.from(authorization, 'utf8') : null;
const sameLength = supplied?.length === expected.length;
const candidate = sameLength && supplied ? supplied : Buffer.alloc(expected.length);
return crypto.timingSafeEqual(candidate, expected) && sameLength;View on GitHub (pinned to ac9a4e9abd)