diff --git a/codex-rs/network-proxy/src/credentialed_routes.rs b/codex-rs/network-proxy/src/credentialed_routes.rs index 2b4af8ae51..b0450c2d4d 100644 --- a/codex-rs/network-proxy/src/credentialed_routes.rs +++ b/codex-rs/network-proxy/src/credentialed_routes.rs @@ -42,6 +42,13 @@ pub struct CredentialedRoutesConfig { impl CredentialedRoutesConfig { pub fn route_prefixes(&self) -> Vec { + if self + .proxy_url + .as_deref() + .is_none_or(|proxy_url| Url::parse(proxy_url).is_err()) + { + return Vec::new(); + } self.routes .iter() .filter_map(|route| parse_route_base_url(route).ok()) @@ -219,6 +226,7 @@ fn route_mitm_hook( proxy_url: &str, ) -> Result { let base_url = parse_route_base_url(route)?; + let proxy_url = Url::parse(proxy_url)?; let host = base_url .host_str() .ok_or_else(|| anyhow::anyhow!("credentialed route must include a host"))? diff --git a/codex-rs/network-proxy/src/credentialed_routes_tests.rs b/codex-rs/network-proxy/src/credentialed_routes_tests.rs index bfd928380e..e6d52a290b 100644 --- a/codex-rs/network-proxy/src/credentialed_routes_tests.rs +++ b/codex-rs/network-proxy/src/credentialed_routes_tests.rs @@ -92,6 +92,15 @@ fn route_prefixes_omit_invalid_values_and_canonicalize_urls() { ); } +#[test] +fn invalid_proxy_url_disables_hooks_and_advertised_prefixes() { + let mut config = proxy_config(vec![route("connector_123", "https://api.example.com/v1")]); + config.proxy_url = Some("not a URL".to_string()); + + assert!(config.mitm_hooks().is_empty()); + assert!(config.route_prefixes().is_empty()); +} + #[tokio::test] async fn credentialed_routes_reloader_rebuilds_generated_hooks() { let mut base_config = NetworkProxyConfig::default();