From e1f24f764dc2780890dadcbade1feb6eb024ad33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Wed, 11 Mar 2026 15:40:37 +0800 Subject: [PATCH] fix(credentials): harden masked debug output (#2114) Signed-off-by: heihutu <30542132+heihutu@users.noreply.github.com> Co-authored-by: houseme Co-authored-by: heihutu <30542132+heihutu@users.noreply.github.com> --- crates/credentials/src/credentials.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/credentials/src/credentials.rs b/crates/credentials/src/credentials.rs index a9f538e53..09c5919fe 100644 --- a/crates/credentials/src/credentials.rs +++ b/crates/credentials/src/credentials.rs @@ -233,15 +233,18 @@ impl<'a> fmt::Debug for Masked<'a> { match self.0 { None => Ok(()), Some(s) => { - let len = s.len(); + let len = s.chars().count(); if len == 0 { Ok(()) } else if len == 1 { write!(f, "***") } else if len == 2 { - write!(f, "{}***|{}", &s[0..1], len) + let first = s.chars().next().ok_or(fmt::Error)?; + write!(f, "{}***|{}", first, len) } else { - write!(f, "{}***{}|{}", &s[0..1], &s[len - 1..], len) + let first = s.chars().next().ok_or(fmt::Error)?; + let last = s.chars().last().ok_or(fmt::Error)?; + write!(f, "{}***{}|{}", first, last, len) } } } @@ -482,5 +485,10 @@ mod tests { // Test longer string assert_eq!(format!("{:?}", Masked(Some("secretpassword"))), "s***d|14"); + + // Test Unicode input should not panic and should keep character boundary + assert_eq!(format!("{:?}", Masked(Some("中"))), "***"); + assert_eq!(format!("{:?}", Masked(Some("中文"))), "中***|2"); + assert_eq!(format!("{:?}", Masked(Some("中文测试"))), "中***试|4"); } }