abhigyanpatwari/GitNexus · error

origin_not_allowed

origin_not_allowed

Error message

This endpoint is restricted to trusted browser origins

What it means

HTTP 403 (body code 'origin_not_allowed') returned by the requireTrustedOrigin middleware guarding mutating routes (POST /api/analyze and /api/analyze/upload, POST /api/embed, the DELETE endpoints, ...): the request carried an Origin header that is neither a loopback origin (localhost/127.x.x.x/::1), nor the server's bound host with matching port, nor the operator-configured GITNEXUS_PUBLIC_ORIGIN. The guard blocks cross-origin browser writes (CSRF/DNS-rebinding shaped requests); requests without an Origin header — curl, CLI, server-side code — always pass.

Source

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

      return;
    }
    try {
      const parsed = new URL(origin);
      const { hostname, protocol } = parsed;
      if (protocol !== 'http:' && protocol !== 'https:') {
        throw new Error('Unsupported origin protocol');
      }
      const matchesBoundHost =
        hostname === normalizedBoundHost &&
        (normalizedBoundPort === undefined || effectivePort(parsed) === normalizedBoundPort);
      if (isLoopbackHostname(hostname) || matchesBoundHost || publicOrigin?.matches(parsed)) {
        next();
        return;
      }
    } catch {
      /* malformed origin → reject */
    }
    res.status(403).json({
      error: 'This endpoint is restricted to trusted browser origins',
      code: 'origin_not_allowed',
    });
  };
}

/**
 * Whether `serve` has any request authentication configured.
 *
 * Nothing can configure it yet: `serve` has no authentication of any kind, and
 * {@link createWriteOriginGuard} passes every request that carries no `Origin`
 * header, so `curl` reaches `POST /api/analyze` and `DELETE /api/repo`
 * unauthenticated. That has been safe only because `serve` bound loopback.
 *
 * So this returns `false` unconditionally, and it is a placeholder on purpose:
 * the `serve` auth change replaces this body, and {@link assertServeAuthForPublicOrigin}
 * and its tests then hold without being rewritten.
 */

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Access the UI via a loopback origin (http://localhost:<port>) — always trusted
  2. Set GITNEXUS_PUBLIC_ORIGIN to the exact public origin (scheme+host+port) the UI is served from, then restart serve
  3. Make ports match: via the bound-host path, the Origin port must equal the server's bound port
  4. For non-browser automation, send no Origin header at all (curl and Node fetch don't add one)

Example fix

# before — LAN access blocked
GITNEXUS_BIND=0.0.0.0 npx gitnexus serve
# browsing http://myhost.local:4747 → writes fail 403 origin_not_allowed

# after
GITNEXUS_BIND=0.0.0.0 GITNEXUS_PUBLIC_ORIGIN=http://myhost.local:4747 npx gitnexus serve
Defensive patterns

Strategy: validation

Validate before calling

// Browser-side pre-flight: is this origin trusted by the server?
const TRUSTED_HOSTS = ['localhost', '127.0.0.1', '::1'];
function originIsTrusted(origin: string, publicOrigin?: string): boolean {
  try {
    const u = new URL(origin);
    return TRUSTED_HOSTS.includes(u.hostname) || u.origin === publicOrigin;
  } catch {
    return false;
  }
}

Try / catch

On 403 with body.code === 'origin_not_allowed', stop retrying (it is deterministic per origin) and surface a configuration hint: use a loopback origin or set GITNEXUS_PUBLIC_ORIGIN server-side.

Prevention

When it happens

Trigger: A page served from another host/port calling the API (dev server on :3000 against serve bound elsewhere); browsing via a LAN IP or hostname (http://myhost.local:4747) without GITNEXUS_PUBLIC_ORIGIN set; an Origin whose port differs from the bound port; a malformed Origin header (parse failure rejects).

Common situations: Exposing serve on 0.0.0.0/LAN and accessing it by IP or mDNS name; reverse proxies rewriting Host/Origin; testing from a phone on the same network; embedded webviews with unexpected origins.

Related errors


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