{"record":{"id":"04726b9d9e260c48","repo":"JuliusBrussee/caveman","slug":"production-refuses-low-diversity-s","errorCode":null,"errorMessage":"production refuses low-diversity %s","messagePattern":"production refuses low-diversity (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"shared/platform/env/env.go","lineNumber":107,"sourceCode":"\tif Bool(\"CAVE_REPLAY_ENABLED\", false) {\n\t\tif err := validateProductionTextSecrets([]string{\"CAVE_ROUTER_REPLAY_TOKEN\"}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn validateProductionPublicURL()\n}\n\nfunc validateProductionTextSecrets(names []string) error {\n\tfor _, name := range names {\n\t\tv := strings.TrimSpace(os.Getenv(name))\n\t\tif v == \"\" || v == \"generated\" || strings.Contains(strings.ToLower(v), \"changeme\") {\n\t\t\treturn fmt.Errorf(\"production refuses default or empty %s\", name)\n\t\t}\n\t\tif len(v) < 32 {\n\t\t\treturn fmt.Errorf(\"production requires %s to contain at least 32 characters\", name)\n\t\t}\n\t\tif distinctBytes([]byte(v)) < 8 {\n\t\t\treturn fmt.Errorf(\"production refuses low-diversity %s\", name)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateProductionPublicURL() error {\n\tpublicURL := strings.TrimSpace(os.Getenv(\"CAVE_PUBLIC_URL\"))\n\tu, err := url.Parse(publicURL)\n\tif err != nil || u.Scheme != \"https\" || u.Hostname() == \"\" || u.User != nil || u.RawQuery != \"\" || u.Fragment != \"\" || (u.Path != \"\" && u.Path != \"/\") {\n\t\treturn fmt.Errorf(\"production requires CAVE_PUBLIC_URL to be an HTTPS origin without credentials, path, query, or fragment\")\n\t}\n\treturn nil\n}\n\nfunc distinctBytes(value []byte) int {\n\tseen := map[byte]struct{}{}\n\tfor _, b := range value {\n\t\tseen[b] = struct{}{}","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/platform/env/env.go#L89-L125","documentation":"Produced by validateProductionTextSecrets (env.go:107): the secret is at least 32 characters long but fewer than 8 distinct byte values appear in it (distinctBytes counts unique bytes). This catches long but low-entropy secrets such as repeated characters or simple patterns, which length alone would let through. The variable name is included.","triggerScenarios":"CAVE_ENV is production and a checked secret of >=32 chars contains fewer than 8 unique bytes - e.g. 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' (1 distinct byte) or 'abcabcabc...' (3 distinct bytes).","commonSituations":"Padding a short password with repetition to satisfy a length rule; placeholder padding like 'x'*40 left by a script; keyboard walks ('qwertyqwerty...'); template strings repeated to fill a field.","solutions":["Generate the secret from a CSPRNG: openssl rand -base64 48 gives high byte diversity by construction.","If humans must type it, use a passphrase from many distinct words/characters rather than repetition.","Verify programmatically before deploy: count distinct bytes and require >=8 (see validation snippet).","Update the secret store and restart so the gate re-evaluates the new value."],"exampleFix":"# before\nCAVE_BOOTSTRAP_TOKEN=00000000000000000000000000000000\n\n# after\nCAVE_BOOTSTRAP_TOKEN=$(openssl rand -base64 48)","handlingStrategy":"validation","validationCode":"func diverse(v string) bool {\n    seen := map[byte]struct{}{}\n    for i := range v { seen[v[i]] = struct{}{} }\n    return len(seen) >= 8\n}","typeGuard":null,"tryCatchPattern":"if err := env.RefuseProductionDefaults(); err != nil {\n    return err // replace repeated-pattern secrets with CSPRNG output\n}","preventionTips":["Never hand-type or pad secrets; always generate.","Run a diversity check in the secret-provisioning pipeline.","Reject repetition-based placeholders in code review of deploy configs."],"tags":["go","production","secrets","entropy","security"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}