{"record":{"id":"d93e9ececf7513b6","repo":"Hmbown/CodeWhale","slug":"refusing-non-loopback-app-server-bind-without-expl","errorCode":null,"errorMessage":"refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN","messagePattern":"refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/app-server/src/lib.rs","lineNumber":889,"sourceCode":"fn resolve_auth_token(options: &AppServerOptions) -> Result<Option<String>> {\n    let configured = options.auth_token.as_ref().map(|token| token.trim());\n    if let Some(token) = configured\n        && token.is_empty()\n    {\n        bail!(\"app-server auth token cannot be empty\");\n    }\n    let has_explicit_token = configured.is_some();\n\n    if options.insecure_no_auth {\n        if !options.listen.ip().is_loopback() {\n            bail!(\"refusing unauthenticated app-server bind on non-loopback address\");\n        }\n        eprintln!(\"warning: app-server HTTP auth disabled by --insecure-no-auth\");\n        return Ok(None);\n    }\n\n    if !has_explicit_token && !options.listen.ip().is_loopback() {\n        bail!(\n            \"refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN\"\n        );\n    }\n\n    let token = configured\n        .map(str::to_string)\n        .unwrap_or_else(|| format!(\"cwapp_{}\", Uuid::new_v4().simple()));\n    for line in app_server_auth_status_lines(has_explicit_token) {\n        eprintln!(\"{line}\");\n    }\n    Ok(Some(token))\n}\n\nfn app_server_auth_status_lines(has_explicit_token: bool) -> Vec<&'static str> {\n    if has_explicit_token {\n        return vec![\"app-server auth: bearer token required for HTTP routes.\"];\n    }\n    vec![","sourceCodeStart":871,"sourceCodeEnd":907,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/app-server/src/lib.rs#L871-L907","documentation":"When the app-server binds to a non-loopback address, an explicit authentication token is mandatory. If no token was configured via `--auth-token` or `CODEWHALE_APP_SERVER_TOKEN`, startup is aborted rather than silently running an unauthenticated network listener. This pairs with the insecure-no-auth guard to ensure any non-local bind is authenticated.","triggerScenarios":"Starting the app-server with a non-loopback `--listen` address while neither `--auth-token` is passed nor `CODEWHALE_APP_SERVER_TOKEN` is set in the environment.","commonSituations":"Deploying the app-server in Docker/Kubernetes or on a remote host and forgetting to set the token env var in the service definition; CI containers binding 0.0.0.0 without credentials.","solutions":["Set `CODEWHALE_APP_SERVER_TOKEN` to a strong random value in the deployment environment.","Pass `--auth-token <token>` on the command line.","Bind to 127.0.0.1 if the client is only ever local."],"exampleFix":"// before (docker-compose)\ncommand: [\"app-server\", \"--listen\", \"0.0.0.0:3927\"]\n// after\nenvironment:\n  - CODEWHALE_APP_SERVER_TOKEN=${APP_SERVER_TOKEN}\ncommand: [\"app-server\", \"--listen\", \"0.0.0.0:3927\"]","handlingStrategy":"validation","validationCode":"// before launching, fail fast if the token is missing for non-loopback binds\nif !listen.is_loopback() && std::env::var(\"CODEWHALE_APP_SERVER_TOKEN\").map_or(true, |t| t.is_empty()) {\n    return Err(\"set CODEWHALE_APP_SERVER_TOKEN before binding non-loopback\".into());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set CODEWHALE_APP_SERVER_TOKEN in every non-local deployment (compose/k8s/CI) as a required secret.","Generate tokens with a CSPRNG (e.g. openssl rand -hex 32).","Add a startup smoke test that asserts the server stays up with the given flags."],"tags":["security","authentication","missing-env-var","cli"],"backgroundTag":"missing-env-var","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}