From 0b33ca99262925558760fcfa2930bee60fe65997 Mon Sep 17 00:00:00 2001 From: Achieve Date: Sat, 28 Mar 2026 22:10:39 +0800 Subject: [PATCH] fix(oauth): tighten legacy state validation and fallback handling (#1701) * fix(oauth): tighten legacy state validation and fallback handling * style: fix formatting * refactor: separate validation checks for clearer error messages --- src/cli/oauth_defaults.rs | 126 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/src/cli/oauth_defaults.rs b/src/cli/oauth_defaults.rs index 384d5833..5628f3d6 100644 --- a/src/cli/oauth_defaults.rs +++ b/src/cli/oauth_defaults.rs @@ -569,6 +569,42 @@ pub async fn sweep_expired_flows(registry: &PendingOAuthRegistry) { const HOSTED_STATE_PREFIX: &str = "ic2"; const HOSTED_STATE_CHECKSUM_BYTES: usize = 12; +/// Maximum length for a legacy flow ID or instance name. +const LEGACY_STATE_MAX_LEN: usize = 128; +/// Minimum length for a legacy flow ID. +const LEGACY_STATE_MIN_LEN: usize = 8; + +/// Validate that a legacy state component (flow_id or instance_name) contains +/// only safe characters: alphanumeric, dash, underscore. +fn is_valid_legacy_state_component(s: &str) -> bool { + !s.is_empty() + && s.len() <= LEGACY_STATE_MAX_LEN + && s.bytes() + .all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_') +} + +fn validate_legacy_flow_id(flow_id: &str) -> Result<(), String> { + if flow_id.len() < LEGACY_STATE_MIN_LEN { + return Err(format!( + "Legacy OAuth flow_id too short ({} chars, minimum {LEGACY_STATE_MIN_LEN})", + flow_id.len() + )); + } + if flow_id.len() > LEGACY_STATE_MAX_LEN { + return Err(format!( + "Legacy OAuth flow_id too long ({} chars, maximum {LEGACY_STATE_MAX_LEN})", + flow_id.len() + )); + } + if !flow_id + .bytes() + .all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_') + { + return Err("Legacy OAuth flow_id contains invalid characters".to_string()); + } + Ok(()) +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct DecodedHostedOAuthState { pub flow_id: String, @@ -653,6 +689,17 @@ pub fn decode_hosted_oauth_state(state: &str) -> Result Result