{"record":{"id":"f0d93feec5f82bd8","repo":"Hmbown/CodeWhale","slug":"unauthenticated-runtime-access-is-loopback-only-remove","errorCode":null,"errorMessage":"Unauthenticated Runtime access is loopback-only; remove --insecure or bind to 127.0.0.1 or ::1","messagePattern":"Unauthenticated Runtime access is loopback-only; remove --insecure or bind to 127\\.0\\.0\\.1 or ::1","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_api.rs","lineNumber":1118,"sourceCode":"/// overlay transport, so a non-loopback listener would expose the Runtime API\n/// to peers that can observe or replay browser traffic.\nfn validate_runtime_listener_security(options: &RuntimeApiOptions) -> Result<()> {\n    if options.port == 0 {\n        bail!(\"Port must be > 0\");\n    }\n    if options.web && options.host != \"127.0.0.1\" {\n        bail!(\"Codewhale web is loopback-only and must bind to 127.0.0.1\");\n    }\n    if options.web && options.insecure_no_auth {\n        bail!(\"Codewhale web requires Runtime authentication; remove --insecure\");\n    }\n    if options.mobile && !is_loopback_bind_host(&options.host) {\n        bail!(\n            \"Codewhale mobile is loopback-only without TLS or a verified overlay; bind to 127.0.0.1 or ::1\"\n        );\n    }\n    if options.insecure_no_auth && !is_loopback_bind_host(&options.host) {\n        bail!(\n            \"Unauthenticated Runtime access is loopback-only; remove --insecure or bind to 127.0.0.1 or ::1\"\n        );\n    }\n    Ok(())\n}\n\nfn is_loopback_bind_host(host: &str) -> bool {\n    host.parse::<IpAddr>()\n        .is_ok_and(|address| address.is_loopback())\n}\n\nfn runtime_bind_address(host: &str, port: u16) -> Result<SocketAddr> {\n    let address = match host.parse::<IpAddr>() {\n        Ok(IpAddr::V6(_)) => format!(\"[{host}]:{port}\"),\n        _ => format!(\"{host}:{port}\"),\n    };\n    address\n        .parse()","sourceCodeStart":1100,"sourceCodeEnd":1136,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_api.rs#L1100-L1136","documentation":"Unauthenticated Runtime access (insecure_no_auth) is only permitted on a loopback bind; on any other host the API would be exposed without credentials. This is the catch-all guard for --insecure with a non-loopback host.","triggerScenarios":"Starting the Runtime API with `--insecure` (and web/mobile checks not already triggering) while `is_loopback_bind_host(&options.host)` is false, e.g. `--host 0.0.0.0` or a LAN address.","commonSituations":"Disabling auth for convenience in a shared/dev box with a permissive bind host; copying a server config that binds all interfaces while --insecure remains set.","solutions":["Remove `--insecure` and configure Runtime authentication","Bind to 127.0.0.1 or ::1 to keep unauthenticated access loopback-only","Audit scripts/containers that inject --host 0.0.0.0 by default"],"exampleFix":"// before\ncodewhale runtime --insecure --host 0.0.0.0\n// after\ncodewhale runtime --insecure --host 127.0.0.1","handlingStrategy":"validation","validationCode":"const LOOPBACK: [&str; 2] = [\"127.0.0.1\", \"::1\"];\nif insecure_flag && !LOOPBACK.contains(&host.as_str()) { return Err(\"--insecure requires a loopback bind\".into()); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer authentication over --insecure in any shared environment","Audit wrapper scripts that set --host 0.0.0.0 by default","Remember the rule: no auth => loopback only"],"tags":["security","loopback","authentication","runtime-api"],"backgroundTag":"conflicting-config-options","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}