Please report suspected vulnerabilities privately through GitHub Security Advisories for this repository. Do not include credentials, internal endpoint URLs, or private configuration files in a public issue.
Model Hub is a local/operator-controlled routing and configuration layer. It is not a network sandbox or a hosted multi-user control plane. Operators remain responsible for access to the host, outbound network policy, and TLS or a trusted private network when traffic leaves the machine.
- Catalogs reference credentials by environment-variable name; credential values do not belong in YAML or browser storage.
- Hub bearer credentials are validated locally and are never forwarded upstream.
- Upstream credentials are selected per endpoint.
- Hub and upstream credentials must have distinct environment-variable names and values; configuration, qualification, and live routing enforce that separation.
- Applied state, revisions, private drafts, activity files, operation history, and Hermes configuration backups are written under the private state/profile boundaries with restrictive permissions.
/healthzis intentionally unauthenticated for service probes and omits endpoint URLs and detailed transport errors. Detailed operator state is behind the protected admin API.
The console is loopback-only by default. If an enabled console is configured to bind a non-loopback host, startup and request handling fail closed unless api_key_env names a non-empty resolved Hub bearer environment variable. A first-run console without an active catalog may not be exposed on a non-loopback host because there is no configured Hub credential. Wildcard listener binds are not treated as loopback for this policy.
POST /admin/v1/session is the only bearer-to-browser exchange. The browser submits the Hub bearer over the same canonical origin and receives a process-local, signed, HttpOnly, SameSite=Strict, path-scoped session cookie plus a session-bound CSRF token. The bearer is not retained in the session registry, written to browser storage, or printed by the launcher. The cookie is opaque to the browser application, and process restart rotates the signing key and revokes existing sessions. DELETE /admin/v1/session revokes the current session.
Every protected admin request requires a valid browser session. A bearer by itself is not an admin session and cannot directly access the admin namespace. State-changing requests additionally require:
- exactly one canonical
Originmatching the request origin; and - the CSRF token bound to that server-side session.
This applies to draft writes/deletes, qualification, apply, rollback, Hermes connection, and operation cancellation. Missing, invalid, cross-origin, malformed, or duplicate-origin requests fail with a stable error envelope rather than exposing diagnostics.
Admin and console responses carry a strict content policy and defensive headers: same-origin scripts/styles/connections and no inline execution, object-src 'none', base-uri 'none', frame-ancestors 'none', form-action 'self', X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer, and X-Frame-Options: DENY. Static assets are package-owned, versioned, allowlisted, and served without remote resources. The public shell is data-free and does not change when private catalog state changes.
Authenticated draft routes are private operator surfaces. They expose bounded candidate YAML and normalized catalog data required by the editor, but reject known credential values and endpoint userinfo before persistence. Draft IDs are opaque, path-shaped IDs are rejected, writes use restrictive file creation and atomic replacement, and optimistic content hashes prevent stale updates or activation.
Qualification, apply, rollback, and Hermes connection are serialized operation workflows. Their public summaries contain fixed lifecycle fields, bounded safe results, and normalized error codes only. Cancellation is cooperative before an irreversible activation cutoff; once activation begins it is not reported as cancellable. A process restart does not turn an incomplete operation into success.
Private activity storage contains bounded JSONL event records and bounded operation history. Events use a fixed schema: safe IDs/tokens, UTC timestamps, severity/category/code, optional alias/replica/operation identifiers, fixed display messages, and finite numeric metadata. Event IDs are monotonic and replay is bounded. Files are rotated and retained under the private state home.
Authenticated admin JSON, admin SSE frames, operation results, the in-memory activity ring, persisted and rotated activity JSONL files, aggregate metrics, and normal application logs are content-free with respect to:
- bearer values and resolved environment values;
- prompt and request bodies;
- generated and upstream response bodies;
- authorization, cookie, and other header material;
- URL userinfo credentials;
- raw exception text, private paths, and detailed transport diagnostics.
Redaction and safe projection happen before event and operation objects are constructed or persisted. Known configured credential values are registered before projections are built, including retained revisions and rollback targets. Observability failures are isolated from inference and must not change inference behavior. This is local operator observability, not an external telemetry pipeline or analytics export.
Two content-bearing surfaces are intentional and bounded by product scope:
- Public OpenAI-compatible inference:
/v1/chat/completionstransparently relays the upstream response body, including streamed and upstream error bodies. This route is the inference product surface and is not an observability projection; callers are responsible for handling the content they requested. - Authenticated private drafts: draft GET/PUT responses may return the bounded candidate YAML and normalized catalog needed by the authenticated editor. Draft content remains private state, is never copied into events/operations/metrics/logs, and is rejected before persistence when it contains known credential values or userinfo-bearing endpoint URLs.
Authenticated admin snapshots may show operator metadata such as configured aliases, credential-presence booleans, endpoint URLs, health state, revisions, fixed metrics, and operation progress. They do not show credential names/values, prompt/response content, headers, raw exceptions, or private filesystem paths. Private status.json may retain bounded transport detail for local troubleshooting; it is never projected through /healthz, snapshots, SSE, operation results, metrics, or the public console. Public and admin unavailable errors use fixed content-free messages.
Model Hub does not launch or manage model-server processes, GPU placement, Kubernetes resources, or a hosted multi-user control plane. It does not provide prompt tracing, token-level telemetry, external analytics, semantic/cost routing, automatic cross-model fallback, or additional inference APIs such as Responses, embeddings, images, or audio. These exclusions are boundaries, not security guarantees for infrastructure outside the Hub.