v0.52.0
Released Aug 12, 2026. Part of the OpenKnowledge changelog.
Minor Changes
Read-posture hardening: every
/apiread and content-asset serve now validates the Host header, closing a DNS-rebinding read-exfil hole on exposed servers.- Previously, mutating routes were Host-gated but reads (
GET /api/*) were Origin-gated only in normal mode. A DNS-rebound page's same-origin GET carries no Origin, so document content could be read cross-origin under exposure. Reads now share the same Host admission writes already use: a request must present a Host in the admitted set (loopback names,server.bindliterals,server.publicUrlhost) or it is refused with403 host-not-allowed. This is the no-auth compensating control — no credentials are involved. - Content-asset serving (
/api/assetsibling static path) is gated the same way, so uploaded images/PDFs/attachments can't be read under a rebound Host either. The extension-less SPA shell stays reachable under any Host (it's public bundle code); only actual content-serve attempts are gated. - If you reach a server by a hostname it hasn't been told about, reads now return
403 host-not-allowed. Declare the name viaserver.publicUrl(or bind to it viaserver.bind) so it's admitted. Loopback access (localhost/127.0.0.1/[::1]) is unaffected, as is any first-party client on a loopback-shaped Host. createAssetServeMiddleware(from@inkeep/open-knowledge-server) now takes a requiredingressPolicy. Surfaces with a resolved runtime pass their boot-built policy; loopback-only surfaces (the Vite dev plugin, theok uisidecar) passbuildIngressPolicy({}). This is a required-parameter addition on a package export, but@inkeep/open-knowledge-serverisprivate: true(never published to npm — internal to the@inkeep/open-knowledgeCLI), so it is not a public-API break; the bump isminoron the only published package, whose CLI command surface is unchanged.
- Previously, mutating routes were Host-gated but reads (
ok start --remote <url>is now a thin alias over the ratifiedserver.*networking keys: it expands toserver.publicUrl(the tunnel URL),server.allowExternalconsent, and a loopback bind, flowing through the same resolution path every other exposure route uses — the dedicated remote-access machinery is gone. Behavior over the tunnel is unchanged (same Host/Origin admission, same stable port default, idle-shutdown stays off), with one improvement: issued URLs (MCPserverUrl,preview_url) now name the tunnel URL instead of an unreachable loopback address. The flag is deprecated and prints a notice pointing at its successors; a new--public-url <url>flag setsserver.publicUrlfor a single run.--remoteand theremote.*config keys keep working for now and will be removed in a later release.