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
- Access the UI via a loopback origin (http://localhost:<port>) — always trusted
- Set GITNEXUS_PUBLIC_ORIGIN to the exact public origin (scheme+host+port) the UI is served from, then restart serve
- Make ports match: via the bound-host path, the Origin port must equal the server's bound port
- 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
- Serve UI and API from one origin when possible
- Configure GITNEXUS_PUBLIC_ORIGIN before exposing serve beyond loopback
- Match scheme+host+port exactly — the check is strict
- Remember CLI/curl calls (no Origin header) are never blocked
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
- Path traversal denied
- Path traversal denied
- [gitnexus serve] Ignoring ${PUBLIC_ORIGIN_ENV}=${raw} — not
- [gitnexus serve] Bound to a wildcard address (${boundHost});
- ${source} entry "${trimmed}" must be an identifier or member
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/a384375b5493f45a.
Report an issue: GitHub.