{"record":{"id":"df032adb87ed8179","repo":"Hmbown/CodeWhale","slug":"loopback-origins-are-not-allowed-in-release-builds","errorCode":null,"errorMessage":"loopback origins are not allowed in release builds","messagePattern":"loopback origins are not allowed in release builds","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/cloud_dispatch.rs","lineNumber":1285,"sourceCode":"        bail!(\"outbound origin must not embed credentials\");\n    }\n    let host = url\n        .host_str()\n        .context(\"outbound origin has no host\")?\n        .trim_end_matches('.')\n        .to_ascii_lowercase();\n    // `Url::host_str` keeps IPv6 brackets; strip them for the checks below.\n    let host = host\n        .strip_prefix('[')\n        .and_then(|inner| inner.strip_suffix(']'))\n        .map(str::to_string)\n        .unwrap_or(host);\n    let loopback_name = host == \"localhost\" || host == \"127.0.0.1\" || host == \"::1\";\n    if loopback_name {\n        if cfg!(debug_assertions) {\n            return Ok(url);\n        }\n        bail!(\"loopback origins are not allowed in release builds\");\n    }\n    if host.ends_with(\".local\") || host.ends_with(\".internal\") {\n        bail!(\"outbound origin must be a public service host\");\n    }\n    if let Ok(ip) = host.parse::<std::net::IpAddr>() {\n        let blocked = match ip {\n            std::net::IpAddr::V4(v4) => {\n                let octets = v4.octets();\n                v4.is_loopback()\n                    || v4.is_private()\n                    || v4.is_link_local()\n                    || v4.is_unspecified()\n                    || v4.is_broadcast()\n                    || v4.is_multicast()\n                    || v4.is_documentation()\n                    // 100.64.0.0/10 (carrier-grade NAT, `is_shared` is\n                    // not stable yet)\n                    || (octets[0] == 100 && (octets[1] & 0b1100_0000) == 0b0100_0000)","sourceCodeStart":1267,"sourceCodeEnd":1303,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/cloud_dispatch.rs#L1267-L1303","documentation":"Loopback hostnames (localhost, 127.0.0.1, ::1) are an explicit escape hatch allowed only in debug builds for local smoke tests against a self-hosted sandbox service. Release builds reject them outright, since production calls must target a real remote service.","triggerScenarios":"Running a release build with DAYTONA_API_URL (or toolbox_url) pointing at localhost/127.0.0.1/::1, e.g. a leftover dev configuration promoted to a packaged binary.","commonSituations":"Shipping a release binary while a local dev endpoint is still configured; CI running release binaries against a local emulator.","solutions":["Point the origin at the real public https endpoint for your environment.","Reproduce the scenario with a debug build (cargo run/dev profile), which permits loopback.","If you genuinely need loopback in release, adjust configuration so the loopback service is reached by other means — there is no flag to bypass this."],"exampleFix":"// before\nexport DAYTONA_API_URL=http://localhost:3000\n// after (release)\nexport DAYTONA_API_URL=https://api.daytona.example.com","handlingStrategy":"validation","validationCode":"let host = reqwest::Url::parse(raw.trim()).ok().and_then(|u| u.host_str().map(str::to_string)).unwrap_or_default();\nlet loopback = matches!(host.to_ascii_lowercase().as_str(), \"localhost\" | \"127.0.0.1\" | \"::1\");\nif loopback && cfg!(not(debug_assertions)) { return Err(\"loopback origin not allowed in release\"); }","typeGuard":null,"tryCatchPattern":"match validate_outbound_origin(raw) {\n    Err(e) if e.to_string().contains(\"loopback origins are not allowed\") => eprintln!(\"configured a dev-only localhost origin; point at the public endpoint\"),\n    other => other?,\n}","preventionTips":["Keep dev loopback settings in debug-only config, never in the packaged default.","Use environment-scoped config files so release gets the real endpoint.","Smoke-test release binaries against the public endpoint before shipping."],"tags":["validation","ssrf","loopback","release-build"],"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-23T08:17:48.524Z"}