{"record":{"id":"238e29b388021613","repo":"deepseek-ai/deepseek-harness","slug":"client-connection-trustedhosts-entry-json-strin","errorCode":null,"errorMessage":"client-connection: trustedHosts entry ${JSON.stringify(entry)} is not a bare host[:port] authority","messagePattern":"client-connection: trustedHosts entry (.+?) is not a bare host\\[:port\\] authority","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/client/connection/src/api-request-trust.ts","lineNumber":57,"sourceCode":"\n/**\n * Assert one configured `trustedHosts` entry is a bare authority (`host` or\n * `host:port`) in canonical form: it must survive WHATWG parsing unchanged\n * (case aside). Anything parsing would silently rewrite is refused as a typo\n * that must fail the load loudly instead of being ignored until requests 403\n * or quietly changing the grant: URL parts beyond the authority\n * (`harness.internal/path`, `user@harness.internal` — which would authorize\n * the embedded hostname), stripped whitespace, a dangling colon or\n * zero-padded port (which would broaden an intended exact-port grant to every\n * port), and non-canonical host spellings (`0x7f.0.0.1`, percent-encoding,\n * unbracketed IPv6; IDN hosts are declared in punycode, the form the wire\n * carries).\n * @param entry - the configured value, verbatim.\n */\nexport function assertTrustedAuthority(entry: string): void {\n  const entryUrl = parseAuthority(entry)\n  if (entryUrl !== undefined && canonicalAuthority(entry, entryUrl) === entry.toLowerCase()) return\n  throw new Error(`client-connection: trustedHosts entry ${JSON.stringify(entry)} is not a bare host[:port] authority`)\n}\n\n/**\n * Canonical form of a parsed authority: `hostname` when no port was written,\n * else `hostname:port`. The port is judged from URL parses under both special\n * schemes (their default ports differ, so `:80` and `:443` still count as\n * explicit), never from the raw string, where WHATWG trimming would misread\n * shapes like `host:port ` as port-less.\n */\nfunction canonicalAuthority(entry: string, entryUrl: URL): string {\n  // An authority that parsed under http cannot fail under https.\n  const port = entryUrl.port !== '' ? entryUrl.port : new URL(`https://${entry}`).port\n  return port === '' ? entryUrl.hostname : `${entryUrl.hostname}:${port}`\n}\n\n/**\n * Whether the request authority matches a `trustedHosts` entry. An entry with\n * an explicit port matches that exact authority; a port-less entry matches the","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/client/connection/src/api-request-trust.ts#L39-L75","documentation":"assertTrustedAuthority backs the client-connection trust fence against DNS rebinding and cross-site requests. Each trustedHosts entry must be a bare host or host:port authority whose canonical WHATWG URL parse equals the entry itself (case aside), so anything parsing would silently rewrite — schemes, paths, userinfo, whitespace, dangling or zero-padded ports, and non-canonical host spellings (hex IPs, percent-encoding, unbracketed IPv6, non-punycode IDN) — fails the plugin load instead of quietly broadening the grant.","triggerScenarios":"Loading the client-connection plugin with trustedHosts values such as https://host:8080, host.internal/path, user@host.internal, host:08080, host:, 0x7f.0.0.1, an unbracketed IPv6 literal, or a unicode IDN name.","commonSituations":"Pasting a full origin URL from the browser into cordis.yml; writing an IDN domain in unicode instead of punycode; leaving a trailing slash or colon; unbracketed IPv6 literals.","solutions":["Write entries as bare lowercase host or host:port — harness.example.com:8080, 192.168.1.10","Encode IDN names in punycode (xn--mnchen-3ya.example) and bracket IPv6 literals ([::1])","Drop schemes, paths, userinfo, surrounding whitespace, and leading zeros in ports; a port-less entry matches every port on that host"],"exampleFix":"# before\nclient-connection:\n  trustedHosts:\n    - https://harness.example.com:8080/\n    - MÜNCHEN.example\n    - 0x7f.0.0.1\n\n# after\nclient-connection:\n  trustedHosts:\n    - harness.example.com:8080\n    - xn--mnchen-3ya.example\n    - 127.0.0.1","handlingStrategy":"validation","validationCode":"// Validate entries with the shipped guard before the plugin loads:\nimport { assertTrustedAuthority } from '@deepseek-ai/dsh-client-connection'\n\nfor (const entry of config.trustedHosts ?? []) assertTrustedAuthority(entry)","typeGuard":"function isBareAuthority(entry: string): boolean {\n  try {\n    const u = new URL(`http://${entry}`)\n    const port = u.port !== '' ? u.port : new URL(`https://${entry}`).port\n    const canonical = port === '' ? u.hostname : `${u.hostname}:${port}`\n    return canonical === entry.toLowerCase()\n  } catch {\n    return false\n  }\n}","tryCatchPattern":null,"preventionTips":["Never paste full origins into trustedHosts; authorities only","Keep entries lowercase and canonical, and run them through assertTrustedAuthority as a config preflight","Prefer LAN IP literals, which the dsh CLI derives itself, over hand-written hostnames"],"tags":["config","security","hostname","validation","cordis-yml"],"backgroundTag":"invalid-host-configuration","analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}