{"record":{"id":"a69551af29b17487","repo":"Hmbown/CodeWhale","slug":"codewhale-mobile-is-loopback-only-without-tls-or-a-verified","errorCode":null,"errorMessage":"Codewhale mobile is loopback-only without TLS or a verified overlay; bind to 127.0.0.1 or ::1","messagePattern":"Codewhale mobile is loopback-only without TLS or a verified overlay; bind to 127\\.0\\.0\\.1 or ::1","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_api.rs","lineNumber":1113,"sourceCode":"    task_manager.shutdown_and_wait().await?;\n    serve_result\n}\n\n/// Mobile control uses plain HTTP only on loopback. It has no TLS or verified\n/// 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>() {","sourceCodeStart":1095,"sourceCodeEnd":1131,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_api.rs#L1095-L1131","documentation":"Mobile control over the Runtime API is plain HTTP with no TLS or verified overlay, so binding to a non-loopback host would expose it to peers that can observe or replay traffic. This bail enforces loopback binding (127.0.0.1 or ::1) whenever mobile mode is on.","triggerScenarios":"Starting the Runtime API with mobile enabled and `is_loopback_bind_host(&options.host)` false — e.g. `--host 0.0.0.0`, an LAN IP, or a hostname resolving off-loopback.","commonSituations":"Trying to use the mobile app from another device by binding 0.0.0.0; Docker/container defaults binding all interfaces; assuming mobile mode implies a secure transport.","solutions":["Bind to 127.0.0.1 or ::1","Reach the runtime from the mobile device via an SSH tunnel or VPN loopback forward","Use the pairing/overlay mechanism instead of a raw non-loopback bind"],"exampleFix":"// before\ncodewhale runtime --mobile --host 0.0.0.0\n// after\ncodewhale runtime --mobile --host 127.0.0.1","handlingStrategy":"validation","validationCode":"const LOOPBACK: [&str; 2] = [\"127.0.0.1\", \"::1\"];\nif mobile_enabled && !LOOPBACK.contains(&host.as_str()) { return Err(\"mobile mode requires a loopback bind\".into()); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Bind mobile mode to 127.0.0.1 or ::1 only","Use tunnels/VPN to reach the runtime from a phone, never a public bind","Treat mobile HTTP as unencrypted and plan transports accordingly"],"tags":["security","loopback","mobile","runtime-api"],"backgroundTag":"invalid-config-value","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"}