Eugeny/tabby · error · Error
Config sync host must use HTTPS (got: ${host})
Error message
Config sync host must use HTTPS (got: ${host}) What it means
Thrown by `ConfigSyncService`'s HTTP helper when the configured sync host does not begin with `https://` (case-insensitive). This is a deliberate security control: the synced payload is YAML merged into local config, including profiles whose `command`/`env` are later executed by the terminal, so a MITM on plaintext HTTP could achieve arbitrary command execution. The check refuses to send over an insecure channel.
Source
Thrown at tabby-settings/src/services/configSync.service.ts:174
await this.platform.saveConfig(yaml.dump(data))
await this.config.load()
await this.config.save()
}
private async request (method: 'GET'|'POST'|'PATCH'|'DELETE', url: string, { data }: { data?: any } = {}) {
if (this.config.store.configSync.host.endsWith('/')) {
this.config.store.configSync.host = this.config.store.configSync.host.slice(0, -1)
}
const host: string = this.config.store.configSync.host
// Refuse to sync configuration over a plaintext channel. The remote
// payload is parsed as YAML and merged into the local config (including
// profiles whose `command`/`env` are later executed by the terminal),
// so a network attacker able to MITM cleartext HTTP could achieve
// arbitrary command execution on the next sync. Require HTTPS.
if (!/^https:\/\//i.test(host)) {
const message = `Config sync host must use HTTPS (got: ${host})`
this.logger.error(message)
throw new Error(message)
}
url = host + url
this.logger.debug(`${method} ${url}`, data)
try {
const response = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${this.config.store.configSync.token}`,
...data !== undefined ? { 'Content-Type': 'application/json' } : {},
},
body: data !== undefined ? JSON.stringify(data) : undefined,
})
if (!response.ok) {
throw new Error(`${method} ${url} failed: ${response.status} ${response.statusText}`)
}
this.logger.debug(response)
// ponytail: DELETE returns empty 204, parse only if there's a body
const text = await response.text()View on GitHub (pinned to 14e2d60b9b)
Solutions
- Configure the sync host with HTTPS: set `configSync.host` to a `https://...` URL (enable TLS on the server or use a reverse proxy with a valid cert).
- For local development, put a TLS-terminating proxy (e.g. Caddy, mkcert, ngrok) in front of the dev server and point the host at its https URL.
- Do NOT weaken the check by allowing http - the guard exists because synced config is executed; if you truly must use plaintext on an isolated network, accept that you are bypassing a security control.
- Validate the host at config-save time and show a UI error before sync is ever attempted.
Example fix
// before
if (!/^https:\/\//i.test(host)) throw new Error(`Config sync host must use HTTPS (got: ${host})`)
// config validation at save time
if (store.configSync?.enabled && !/^https:\/\//i.test(store.configSync.host)) {
notifications.error('Config sync host must be an https:// URL')
return false
} Defensive patterns
Strategy: validation
Validate before calling
function isValidHttpsHost (host: string): boolean {
return /^https:\/\//i.test(host)
}
const host = config.store.configSync.host
if (config.store.configSync.enabled && !isValidHttpsHost(host)) {
throw new Error('Config sync requires an https:// host')
} Type guard
function isHttpsUrl (u: string): boolean { return /^https:\/\//i.test(u) } Prevention
- Always configure configSync.host with https:// (use a TLS-terminating proxy if needed).
- Validate the host at config-save time so the user is warned before any sync attempt.
- Never disable the HTTPS check - synced config is executed and plaintext is unsafe.
- For local dev, front the server with mkcert/Caddy/ngrok to obtain an https URL.
When it happens
Trigger: Setting `configSync.host` to an `http://` URL (or any non-https scheme) and triggering any sync operation (push/pull/auto-sync). The regex `/^https:\/\//i` fails and the request is aborted before `fetch`.
Common situations: User pastes a self-hosted sync URL without TLS; using `http://` for a localhost dev server; misconfigured reverse proxy that terminates TLS but the configured host still says http; copy-paste from a tool that strips the scheme.
Related errors
- Vault not configured
- ${method} ${url} failed: ${response.status} ${response.statu
- Did not find any bootstrap components. Are there any plugins
- Not found
- No available file providers
AI-assisted analysis of Eugeny/tabby@14e2d60b9b (2026-08-12).
Data as JSON: /api/errors/7b9da8cffe2c01ce.
Report an issue: GitHub.