@@ -17,7 +17,23 @@ impl<'a> DetectionHelper<'a> {
1717
1818 /// Normalize a path for comparison.
1919 pub fn normalize_path ( path : & str ) -> String {
20- let mut normalized = path. replace ( "//" , "/" ) ;
20+ let mut normalized = String :: with_capacity ( path. len ( ) ) ;
21+ let mut previous_was_slash = false ;
22+
23+ for ch in path. chars ( ) {
24+ let ch = if ch == '\\' { '/' } else { ch } ;
25+
26+ if ch == '/' {
27+ if previous_was_slash {
28+ continue ;
29+ }
30+ previous_was_slash = true ;
31+ } else {
32+ previous_was_slash = false ;
33+ }
34+
35+ normalized. push ( ch) ;
36+ }
2137
2238 // Handle trailing slashes
2339 while normalized. len ( ) > 1 && normalized. ends_with ( '/' ) {
@@ -29,9 +45,6 @@ impl<'a> DetectionHelper<'a> {
2945 normalized = normalized. replacen ( '~' , "/home" , 1 ) ;
3046 }
3147
32- // Handle Windows paths
33- normalized = normalized. replace ( '\\' , "/" ) ;
34-
3548 normalized
3649 }
3750
@@ -994,3 +1007,33 @@ impl<'a> DetectionHelper<'a> {
9941007 }
9951008 }
9961009}
1010+
1011+ #[ cfg( test) ]
1012+ mod tests {
1013+ use super :: * ;
1014+
1015+ #[ test]
1016+ fn normalize_path_collapses_repeated_slashes ( ) {
1017+ assert_eq ! (
1018+ DetectionHelper :: normalize_path( "///etc/shadow" ) ,
1019+ "/etc/shadow"
1020+ ) ;
1021+ assert_eq ! (
1022+ DetectionHelper :: normalize_path( "////etc//shadow///" ) ,
1023+ "/etc/shadow"
1024+ ) ;
1025+ assert_eq ! (
1026+ DetectionHelper :: normalize_path( "C:\\ \\ Windows\\ System32" ) ,
1027+ "C:/Windows/System32"
1028+ ) ;
1029+ }
1030+
1031+ #[ test]
1032+ fn sensitive_path_detects_repeated_leading_slashes ( ) {
1033+ let config = PolicyConfig :: default ( ) ;
1034+ let helper = DetectionHelper :: new ( & config) ;
1035+
1036+ assert ! ( helper. is_sensitive_path( "///etc/shadow" ) ) ;
1037+ assert ! ( helper. is_sensitive_path( "////etc//shadow" ) ) ;
1038+ }
1039+ }
0 commit comments