1use anyhow::{bail, Result};
4
5use crate::constants::*;
6
7pub fn detect_windows_attacks(path: &str) -> Result<()> {
9 if path.contains(':') {
12 let starts_with_drive = path.len() >= 2 &&
14 path.chars().nth(0).map_or(false, |c| c.is_ascii_alphabetic()) &&
15 path.chars().nth(1) == Some(':');
16
17 if !starts_with_drive {
18 bail!("Colon detected in path (possible NTFS stream or device): {}", path);
20 } else if path.len() > 2 {
21 if path[2..].contains(':') {
23 bail!("NTFS alternate data stream syntax detected: {}", path);
24 }
25 }
26 }
27
28 if path.starts_with("\\\\") || path.starts_with("//") {
30 bail!("UNC path detected: {}", path);
31 }
32
33 if path.starts_with("\\\\?\\") || path.starts_with("\\\\.\\") {
35 bail!("Windows extended-length path prefix detected: {}", path);
36 }
37
38 let path_upper = path.to_uppercase();
40 if path_upper.starts_with("\\\\.\\") || path_upper.contains("\\DEVICE\\") {
41 bail!("Windows device path detected");
42 }
43
44 if let Some(last_component) = path.split(&['/', '\\'][..]).last() {
46 if last_component.ends_with('.') && last_component != "." && last_component != ".." {
47 bail!("Trailing dot detected in path component (Windows exploit): {}", last_component);
48 }
49
50 if last_component.ends_with(' ') {
52 bail!("Trailing space detected in path component (Windows exploit)");
53 }
54 }
55
56 Ok(())
57}
58
59pub fn detect_separator_manipulation(path: &str) -> Result<()> {
61 if path.contains("//") || path.contains("\\\\") {
63 if !path.starts_with("//") && !path.starts_with("\\\\") {
65 bail!("Multiple consecutive path separators detected");
66 }
67 }
68
69 if path.contains('/') && path.contains('\\') {
71 bail!("Mixed path separators detected (possible evasion)");
72 }
73
74 for sep in DANGEROUS_SEPARATORS.iter() {
76 if path.contains(*sep) {
77 bail!("Unusual separator character detected in path");
78 }
79 }
80
81 Ok(())
82}
83
84pub fn detect_advanced_traversal(path: &str) -> Result<()> {
86 for pattern in TRAVERSAL_PATTERNS.iter() {
88 if path.contains(pattern) {
89 bail!("Directory traversal pattern detected: {}", pattern);
90 }
91 }
92
93 for pattern in NESTED_TRAVERSAL_PATTERNS.iter() {
95 if path.contains(pattern) {
96 bail!("Nested traversal pattern detected: {}", pattern);
97 }
98 }
99
100 if path.contains("\\x2e") || path.contains("\\x2f") || path.contains("\\x5c") {
102 bail!("Hex-encoded path characters detected");
103 }
104
105 Ok(())
106}
107
108pub fn validate_special_paths(path: &str) -> Result<()> {
110 let path_lower = path.to_lowercase();
111 for dangerous in SYSTEM_PATHS.iter() {
112 if path_lower.starts_with(&dangerous.to_lowercase()) {
113 bail!("Access to sensitive system path denied: {}", dangerous);
114 }
115 }
116
117 Ok(())
118}
119
120pub fn detect_protocol_schemes(path: &str) -> Result<()> {
122 let path_lower = path.to_lowercase();
123
124 if path_lower.starts_with("file://") || path_lower.starts_with("file:/") {
126 bail!("File protocol scheme detected in path");
127 }
128
129 if path_lower.starts_with("http://") || path_lower.starts_with("https://") {
131 bail!("HTTP protocol scheme detected in path (possible SSRF)");
132 }
133
134 for protocol in DANGEROUS_PROTOCOLS.iter() {
136 if path_lower.starts_with(protocol) {
137 bail!("Dangerous protocol scheme detected: {}", protocol);
138 }
139 }
140
141 Ok(())
142}
143
144pub fn detect_suspicious_patterns(path: &str) -> Result<()> {
146 for pattern in SUSPICIOUS_PATTERNS.iter() {
147 if path.contains(pattern) {
148 bail!("Suspicious pattern '{}' detected in path: {}", pattern, path);
149 }
150 }
151
152 Ok(())
153}