From d0456ef11701d4f6194c2552b5d90b962cfeee1f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 26 Jul 2026 17:54:33 +0000 Subject: [PATCH 1/2] fix(kms): validate onboarding domains --- dstack/kms/src/onboard_service.rs | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dstack/kms/src/onboard_service.rs b/dstack/kms/src/onboard_service.rs index d3db6485b..ed244faf5 100644 --- a/dstack/kms/src/onboard_service.rs +++ b/dstack/kms/src/onboard_service.rs @@ -72,8 +72,28 @@ impl RpcCall for OnboardHandler { } } +fn validate_onboarding_domain(domain: &str) -> Result<()> { + if domain.is_empty() || domain.len() > 253 || !domain.is_ascii() { + bail!("domain must be a non-empty ASCII DNS name of at most 253 bytes"); + } + for label in domain.split('.') { + if label.is_empty() + || label.len() > 63 + || label.starts_with('-') + || label.ends_with('-') + || !label + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-') + { + bail!("domain contains an invalid DNS label"); + } + } + Ok(()) +} + impl OnboardRpc for OnboardHandler { async fn bootstrap(self, request: BootstrapRequest) -> Result { + validate_onboarding_domain(&request.domain)?; ensure_self_kms_allowed(&self.state.config, &self.state.attestation_verifier) .await .context("KMS is not allowed to bootstrap")?; @@ -98,6 +118,7 @@ impl OnboardRpc for OnboardHandler { } async fn onboard(self, request: OnboardRequest) -> Result { + validate_onboarding_domain(&request.domain)?; let source_url = request.source_url.trim_end_matches('/').to_string(); let source_url = if source_url.ends_with("/prpc") { source_url @@ -578,6 +599,7 @@ pub(crate) async fn update_certs(cfg: &KmsConfig) -> Result<()> { } pub(crate) async fn bootstrap_keys(cfg: &KmsConfig, verifier: &AttestationVerifier) -> Result<()> { + validate_onboarding_domain(&cfg.onboard.auto_bootstrap_domain)?; ensure_self_kms_allowed(cfg, verifier) .await .context("KMS is not allowed to auto-bootstrap")?; @@ -626,3 +648,27 @@ async fn gen_ra_cert(ca_cert_pem: String, ca_key_pem: String) -> Result<(String, let cert = ca.sign(req).context("Failed to sign certificate")?; Ok((cert.pem(), key.serialize_pem())) } + +#[cfg(test)] +mod tests { + use super::validate_onboarding_domain; + + #[test] + fn onboarding_domain_accepts_dns_name() { + validate_onboarding_domain("kms.example.com").unwrap(); + } + + #[test] + fn onboarding_domain_rejects_empty_overlong_and_invalid_labels() { + for domain in [ + "", + &"a".repeat(254), + "-kms.example.com", + "kms-.example.com", + "kms..example.com", + "kms_example.com", + ] { + assert!(validate_onboarding_domain(domain).is_err(), "{domain:?}"); + } + } +} From e1270fdf2ce5768f089bdeb156bbb35ce9edf15f Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sun, 26 Jul 2026 17:55:26 +0000 Subject: [PATCH 2/2] fix(kms): integrate onboarding domain tests --- dstack/kms/src/onboard_service.rs | 44 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/dstack/kms/src/onboard_service.rs b/dstack/kms/src/onboard_service.rs index ed244faf5..5e54c17f0 100644 --- a/dstack/kms/src/onboard_service.rs +++ b/dstack/kms/src/onboard_service.rs @@ -363,6 +363,26 @@ mod tests { assert_eq!(response.eth_rpc_url, "https://rpc.example"); assert_eq!(response.kms_contract_address, "0x1234"); } + + #[test] + fn onboarding_domain_accepts_dns_name() { + validate_onboarding_domain("kms.example.com").unwrap(); + } + + #[test] + fn onboarding_domain_rejects_empty_overlong_and_invalid_labels() { + let overlong = "a".repeat(254); + for domain in [ + "", + overlong.as_str(), + "-kms.example.com", + "kms-.example.com", + "kms..example.com", + "kms_example.com", + ] { + assert!(validate_onboarding_domain(domain).is_err(), "{domain:?}"); + } + } } struct Keys { @@ -648,27 +668,3 @@ async fn gen_ra_cert(ca_cert_pem: String, ca_key_pem: String) -> Result<(String, let cert = ca.sign(req).context("Failed to sign certificate")?; Ok((cert.pem(), key.serialize_pem())) } - -#[cfg(test)] -mod tests { - use super::validate_onboarding_domain; - - #[test] - fn onboarding_domain_accepts_dns_name() { - validate_onboarding_domain("kms.example.com").unwrap(); - } - - #[test] - fn onboarding_domain_rejects_empty_overlong_and_invalid_labels() { - for domain in [ - "", - &"a".repeat(254), - "-kms.example.com", - "kms-.example.com", - "kms..example.com", - "kms_example.com", - ] { - assert!(validate_onboarding_domain(domain).is_err(), "{domain:?}"); - } - } -}