{"record":{"id":"398f9edc95a114dc","repo":"nautechsystems/nautilus_trader","slug":"description-endpoint-must-use-https-unless-its-h","errorCode":null,"errorMessage":"{description} endpoint must use HTTPS unless its host is a canonical loopback IP literal","messagePattern":"(.+?) endpoint must use HTTPS unless its host is a canonical loopback IP literal","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/http.rs","lineNumber":930,"sourceCode":"pub(crate) fn validate_execution_endpoint(\n    endpoint: &str,\n    description: &str,\n) -> anyhow::Result<Url> {\n    let url =\n        Url::parse(endpoint).map_err(|_| anyhow::anyhow!(\"Invalid {description} endpoint\"))?;\n    anyhow::ensure!(\n        matches!(url.scheme(), \"http\" | \"https\"),\n        \"{description} endpoint must use HTTPS or canonical loopback HTTP\"\n    );\n    anyhow::ensure!(\n        url.host().is_some(),\n        \"{description} endpoint host is required\"\n    );\n    anyhow::ensure!(\n        url.fragment().is_none(),\n        \"{description} endpoint fragments are unsupported\"\n    );\n    anyhow::ensure!(\n        url.scheme() == \"https\" || is_canonical_loopback_endpoint(endpoint),\n        \"{description} endpoint must use HTTPS unless its host is a canonical loopback IP literal\"\n    );\n    Ok(url)\n}\n\nfn is_canonical_loopback_endpoint(endpoint: &str) -> bool {\n    let Some((scheme, rest)) = endpoint.split_once(\"://\") else {\n        return false;\n    };\n\n    if !scheme.eq_ignore_ascii_case(\"http\") && !scheme.eq_ignore_ascii_case(\"https\") {\n        return false;\n    }\n    let authority_end = rest.find(['/', '?', '#']).unwrap_or(rest.len());\n    let authority = &rest[..authority_end];\n    if authority.is_empty() || authority.contains('@') {\n        return false;","sourceCodeStart":912,"sourceCodeEnd":948,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/http.rs#L912-L948","documentation":"Thrown by `validate_execution_endpoint` as the security gate: cleartext `http://` is only allowed when the host is a canonical loopback IP literal (127.0.0.1, [::1], etc.). Any non-loopback host must use HTTPS to protect RPC traffic (including credentials) in transit.","triggerScenarios":"Configuring an execution endpoint as `http://` against a non-loopback host — e.g. `http://node.internal:8545`, `http://192.168.1.10:8545`, or a public `http://` provider URL — via `new` or `normalize_endpoint`.","commonSituations":"Local dev config carried into staging/production where the node is remote; internal-network nodes assumed safe enough for plaintext; providers still advertising plain-HTTP endpoints.","solutions":["Switch the endpoint to `https://` (enable TLS on the node or put it behind a TLS-terminating proxy).","For local development, use the literal loopback form `http://127.0.0.1:8545` (or `http://[::1]:8545`), not `localhost` or a LAN IP.","If tests need cleartext, target a loopback address so the canonical-loopback check passes."],"exampleFix":"// before\nlet endpoint = \"http://192.168.1.10:8545\"; // LAN IP over HTTP rejected\n// after\nlet endpoint = \"https://192.168.1.10:8545\"; // or http://127.0.0.1:8545 for local dev","handlingStrategy":"validation","validationCode":"let url = url::Url::parse(endpoint)?;\nlet loopback = matches!(url.host_str(), Some(h) if h == \"127.0.0.1\" || h == \"[::1]\");\nanyhow::ensure!(url.scheme() == \"https\" || loopback,\n    \"non-loopback endpoint '{endpoint}' must use https\");","typeGuard":"fn is_tls_safe_endpoint(s: &str) -> bool {\n    url::Url::parse(s).map(|u| {\n        u.scheme() == \"https\"\n            || matches!(u.host_str(), Some(\"127.0.0.1\") | Some(\"[::1]\"))\n    }).unwrap_or(false)\n}","tryCatchPattern":"match HttpRpcClient::new(endpoint) {\n    Err(e) if e.to_string().contains(\"canonical loopback IP literal\") => {\n        return Err(anyhow::anyhow!(\"refusing cleartext HTTP to non-loopback host '{endpoint}'; enable TLS\"));\n    }\n    other => other,\n}","preventionTips":["Default all remote endpoints to https:// in every environment (dev/staging/prod).","Reserve plain http:// for literal 127.0.0.1 / [::1] in local development only.","Never promote local http://LAN-IP configs to shared/staging environments.","Terminate TLS with a proxy (nginx/Caddy) in front of internal nodes."],"tags":["security","tls","url","config"],"backgroundTag":"insecure-http-endpoint","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}