{"record":{"id":"a73c0b2a0e1666e6","repo":"JuliusBrussee/caveman","slug":"production-refuses-s-true-it-disables-chain-and","errorCode":null,"errorMessage":"production refuses %s=true: it disables chain and hostname verification, so any in-path party can read or forge telemetry — use %s instead","messagePattern":"production refuses (.+?)=true: it disables chain and hostname verification, so any in-path party can read or forge telemetry — use (.+?) instead","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"shared/platform/chhttp/chhttp.go","lineNumber":125,"sourceCode":"// definitions of \"prod\" would let one gate fire while the other stayed asleep.\nfunc production() bool {\n\treturn env.IsProduction()\n}\n\n// tlsClientConfig builds the ClickHouse TLS configuration from the environment,\n// or (nil, nil) when no CLICKHOUSE_TLS_* knob is set — in which case callers keep\n// the stock transport (system roots, hostname verified against the URL host).\n//\n// It fails CLOSED: a prod skip-verify request, an unreadable CA file, or a CA\n// file with no parseable certificate all return an error rather than quietly\n// downgrading to the ambient trust store.\nfunc tlsClientConfig() (*tls.Config, error) {\n\tserverName := strings.TrimSpace(env.String(serverNameEnv, \"\"))\n\tcaFile := strings.TrimSpace(env.String(caFileEnv, \"\"))\n\tskipVerify := env.Bool(skipVerifyEnv, false)\n\n\tif skipVerify && production() {\n\t\treturn nil, fmt.Errorf(\"production refuses %s=true: it disables chain and hostname verification, so any in-path party can read or forge telemetry — use %s instead\", skipVerifyEnv, serverNameEnv)\n\t}\n\tif serverName == \"\" && caFile == \"\" && !skipVerify {\n\t\treturn nil, nil\n\t}\n\n\tcfg := &tls.Config{\n\t\tMinVersion: tls.VersionTLS12,\n\t\tServerName: serverName,\n\t\t// #nosec G402 -- refused in production above; non-prod only, and loudly\n\t\t// warned about by ValidateProduction at startup.\n\t\tInsecureSkipVerify: skipVerify,\n\t}\n\tif caFile != \"\" {\n\t\troots, err := rootsWithCAFile(caFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcfg.RootCAs = roots","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/platform/chhttp/chhttp.go#L107-L143","documentation":"Thrown by tlsClientConfig in the ClickHouse telemetry HTTP package when CLICKHOUSE_TLS_INSECURE_SKIP_VERIFY=true is set while the process runs in production (per env.IsProduction / CAVE_ENV). Disabling TLS verification would let any on-path party read or forge telemetry, so production refuses to boot the client with it; the error message points at CLICKHOUSE_TLS_SERVER_NAME as the safe alternative for mismatched-hostname setups.","triggerScenarios":"Setting CLICKHOUSE_TLS_INSECURE_SKIP_VERIFY=true in an environment where CAVE_ENV marks the process production (e.g. CAVE_ENV=production), and any ClickHouse client path that builds the TLS config (boot or first telemetry client construction).","commonSituations":"A dev workaround (self-signed cert on a local ClickHouse) copied into the production env file; a private CA whose hostname doesn't match the URL host, worked around with skip-verify instead of CLICKHOUSE_TLS_SERVER_NAME; k8s ConfigMap promoting staging env wholesale.","solutions":["Remove CLICKHOUSE_TLS_INSECURE_SKIP_VERIFY from the production environment.","If the certificate hostname doesn't match the URL host, set CLICKHOUSE_TLS_SERVER_NAME=<expected certificate name> instead.","For a private CA, install the CA bundle via CLICKHOUSE_TLS_CA_FILE (system pool + bundle, still verified) rather than skipping verification.","Keep skip-verify only in non-prod environments and expect a startup warning from ValidateProduction there."],"exampleFix":"# before (production env)\nCLICKHOUSE_TLS_INSECURE_SKIP_VERIFY=true\n\n# after\n# cert hostname != URL host:\nCLICKHOUSE_TLS_SERVER_NAME=clickhouse.internal.corp\n# or trust a private CA while keeping verification:\nCLICKHOUSE_TLS_CA_FILE=/etc/secrets/clickhouse-ca.pem","handlingStrategy":"validation","validationCode":"if os.Getenv(\"CLICKHOUSE_TLS_INSECURE_SKIP_VERIFY\") == \"true\" && isProdEnv() {\n    return errors.New(\"refuse to start: insecure TLS skip-verify is not allowed in production\")\n}","typeGuard":null,"tryCatchPattern":"Do not catch-and-continue: this error is a deliberate boot-time refusal. Let startup fail and fix the environment, otherwise you are running the exact risk the guard exists to prevent.","preventionTips":["Keep production env files free of CLICKHOUSE_TLS_INSECURE_SKIP_VERIFY; audit ConfigMaps/secrets during promotion from staging.","For hostname mismatches use CLICKHOUSE_TLS_SERVER_NAME; for private CAs use CLICKHOUSE_TLS_CA_FILE.","Add a deploy-time check that refuses configs combining production CAVE_ENV with skip-verify."],"tags":["clickhouse","tls","security","configuration","production"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}