{"record":{"id":"8fd1d66666f907ff","repo":"Hmbown/CodeWhale","slug":"outbound-origin-must-not-target-a-loopback-private-or","errorCode":null,"errorMessage":"outbound origin must not target a loopback, private, or reserved address","messagePattern":"outbound origin must not target a loopback, private, or reserved address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/cloud_dispatch.rs","lineNumber":1326,"sourceCode":"                    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                        || (octets[0] == 100 && (octets[1] & 0b1100_0000) == 0b0100_0000)\n                } else {\n                    v6.is_loopback()\n                        || v6.is_unspecified()\n                        || v6.is_multicast()\n                        || (v6.segments()[0] & 0xfe00) == 0xfc00\n                        || (v6.segments()[0] & 0xffc0) == 0xfe80\n                }\n            }\n        };\n        if blocked {\n            bail!(\"outbound origin must not target a loopback, private, or reserved address\");\n        }\n    }\n    if url.scheme() != \"https\" {\n        bail!(\"outbound origin must use https\");\n    }\n    Ok(url)\n}\n\n/// Meter one closed interval on a dispatched cloud job.\n///\n/// The job's sandbox id must match the provider observation. Wall-clock after\n/// create is not enough: the observation has to be provider-accepted active\n/// time bound to the immutable admission.\npub fn meter_cloud_job(\n    job: &CloudJob,\n    admission: &ComputerAdmission,\n    observation: ProviderObservation,\n) -> Result<ComputerMeterReceipt, ComputerMeterError> {","sourceCodeStart":1308,"sourceCodeEnd":1344,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/cloud_dispatch.rs#L1308-L1344","documentation":"If the host parses as an IP address, the validator blocks loopback, private, link-local, unspecified, broadcast, multicast, documentation ranges, carrier-grade NAT (100.64.0.0/10), and their IPv6/IPv4-mapped equivalents. This prevents credential-bearing requests from being aimed at internal network addresses (SSRF).","triggerScenarios":"Configuring an origin whose host is a raw IP like 192.168.1.10, 10.0.0.5, 169.254.169.254 (metadata service), ::1, or fd00::1.","commonSituations":"Self-hosted sandbox service on a LAN addressed by IP; attempting to hit a cloud metadata endpoint; IPv6 private addresses in config.","solutions":["Give the service a public https hostname and configure that instead of the raw internal IP.","Route through a reverse proxy on a public address.","For local development, use a debug build with localhost/127.0.0.1, which has its own explicit path."],"exampleFix":"// before\nexport DAYTONA_API_URL=http://192.168.1.10:8080\n// after\nexport DAYTONA_API_URL=https://sandbox.example.com","handlingStrategy":"validation","validationCode":"if let Ok(ip) = host.trim_end_matches('.').parse::<std::net::IpAddr>() {\n    let private = match ip { IpAddr::V4(v4) => v4.is_private() || v4.is_loopback() || v4.is_link_local(), IpAddr::V6(v6) => v6.is_loopback() || (v6.segments()[0] & 0xfe00) == 0xfc00 || (v6.segments()[0] & 0xffc0) == 0xfe80 };\n    if private { return Err(\"origin must be a public IP/host\"); }\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = validate_outbound_origin(raw) {\n    if e.to_string().contains(\"loopback, private, or reserved\") {\n        eprintln!(\"origin targets a non-public address (SSRF guard): {raw}\");\n    }\n}","preventionTips":["Use hostnames backed by public DNS instead of raw internal IPs.","Never configure cloud-metadata or LAN addresses as outbound origins.","Validate endpoints at startup, before any credential-bearing call."],"tags":["ssrf","security","validation","ip-address"],"backgroundTag":"invalid-url","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"}