{"record":{"id":"70d4d9fe4524573f","repo":"JuliusBrussee/caveman","slug":"caveman-auth-token-must-be-at-least-d-bytes","errorCode":null,"errorMessage":"CAVEMAN_AUTH_TOKEN must be at least %d bytes","messagePattern":"CAVEMAN_AUTH_TOKEN must be at least (.+?) bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/config/config.go","lineNumber":298,"sourceCode":"\tselector := (&httpproxy.Config{HTTPProxy: raw, HTTPSProxy: raw, NoProxy: env.String(\"NO_PROXY\", env.String(\"no_proxy\", \"\"))}).ProxyFunc()\n\treturn func(req *http.Request) (*url.URL, error) { return selector(req.URL) }, nil\n}\n\n// minAuthTokenBytes is the floor for the inbound shared secret. The token is the\n// only gate in front of every configured provider credential once the proxy is\n// reachable off-host, so a short one is not a weaker deployment, it is an open one.\nconst minAuthTokenBytes = 16\n\n// validateAuthToken refuses a token that cannot survive one HTTP header value:\n// control bytes terminate the field, and a space would split scheme from value in\n// `Authorization: Bearer <token>`. The error never echoes the value — it is a\n// secret and this message reaches the proxy log.\nfunc validateAuthToken(token string) error {\n\tif token == \"\" {\n\t\treturn nil\n\t}\n\tif len(token) < minAuthTokenBytes {\n\t\treturn fmt.Errorf(\"CAVEMAN_AUTH_TOKEN must be at least %d bytes\", minAuthTokenBytes)\n\t}\n\tfor _, r := range token {\n\t\tif r == ' ' || r < 0x20 || r == 0x7f {\n\t\t\treturn fmt.Errorf(\"CAVEMAN_AUTH_TOKEN must contain no spaces or control characters\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// validateListen keeps standalone's BYOK proxy local to one operator unless an\n// inbound credential gates it. Binding an empty, wildcard, or non-loopback host\n// would expose every configured provider credential to the network with no\n// inbound authentication; authenticated says CAVEMAN_AUTH_TOKEN is set, so\n// standalone.Auth rejects every request that does not present it and the wider\n// bind becomes a deliberate operator choice instead of an accident.\nfunc validateListen(listen string, authenticated bool) error {\n\thost, port, err := net.SplitHostPort(strings.TrimSpace(listen))\n\tif err != nil || port == \"\" {","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/config/config.go#L280-L316","documentation":"CAVEMAN_AUTH_TOKEN is set but shorter than the configured minimum (minAuthTokenBytes). Short tokens are brute-forceable, so Load rejects them during startup rather than accepting weak inbound authentication for the standalone BYOK proxy.","triggerScenarios":"Exporting CAVEMAN_AUTH_TOKEN to a string under minAuthTokenBytes bytes (e.g. \"abc\", \"token1\") and running config.Load; CI or scripts generating short placeholder secrets.","commonSituations":"Developer testing locally with a trivial token like \"test\"; ops checklist leaving a stub value in .env; truncated secret pasted from a secrets manager.","solutions":["Generate a longer token, e.g. `openssl rand -hex 32`, and set CAVEMAN_AUTH_TOKEN to it.","Clear the variable entirely (empty string is allowed and means auth disabled) if non-loopback binding is not needed.","If the value comes from a .env file or shell profile, fix the stale short value there and reload the shell."],"exampleFix":"// before\nexport CAVEMAN_AUTH_TOKEN=\"abc123\"\n// after\nexport CAVEMAN_AUTH_TOKEN=\"$(openssl rand -hex 32)\"","handlingStrategy":"validation","validationCode":"token := os.Getenv(\"CAVEMAN_AUTH_TOKEN\")\nif token != \"\" && len(token) < minAuthTokenBytes {\n    return fmt.Errorf(\"CAVEMAN_AUTH_TOKEN must be at least %d bytes\", minAuthTokenBytes)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate tokens with openssl rand -hex 32 rather than by hand.","Never commit placeholder short tokens to .env files.","Pre-flight check secrets length in deployment scripts."],"tags":["env-var","auth","config"],"backgroundTag":"invalid-env-var-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}