1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct LLMSecurityConfig {
8 pub enable_injection_detection: bool,
10
11 pub enable_output_validation: bool,
13
14 pub max_code_size_bytes: usize,
16
17 pub strict_mode: bool,
19
20 pub log_attacks: bool,
22
23 pub max_llm_calls_per_hour: u32,
25}
26
27impl Default for LLMSecurityConfig {
28 fn default() -> Self {
29 Self {
30 enable_injection_detection: true,
31 enable_output_validation: true,
32 max_code_size_bytes: crate::constants::DEFAULT_MAX_CODE_SIZE_BYTES,
33 strict_mode: true,
34 log_attacks: true,
35 max_llm_calls_per_hour: crate::constants::DEFAULT_MAX_LLM_CALLS_PER_HOUR,
36 }
37 }
38}
39
40impl LLMSecurityConfig {
41 pub fn new(
43 enable_injection_detection: bool,
44 enable_output_validation: bool,
45 max_code_size_bytes: usize,
46 strict_mode: bool,
47 ) -> Self {
48 Self {
49 enable_injection_detection,
50 enable_output_validation,
51 max_code_size_bytes,
52 strict_mode,
53 log_attacks: true,
54 max_llm_calls_per_hour: crate::constants::DEFAULT_MAX_LLM_CALLS_PER_HOUR,
55 }
56 }
57
58 pub fn permissive() -> Self {
60 Self {
61 enable_injection_detection: false,
62 enable_output_validation: false,
63 max_code_size_bytes: crate::constants::DEFAULT_MAX_CODE_SIZE_BYTES,
64 strict_mode: false,
65 log_attacks: false,
66 max_llm_calls_per_hour: crate::constants::DEFAULT_MAX_LLM_CALLS_PER_HOUR,
67 }
68 }
69
70 pub fn strict() -> Self {
72 Self {
73 enable_injection_detection: true,
74 enable_output_validation: true,
75 max_code_size_bytes: 100_000, strict_mode: true,
77 log_attacks: true,
78 max_llm_calls_per_hour: 50, }
80 }
81
82 pub fn validate(&self) -> Result<(), String> {
84 if self.max_code_size_bytes == 0 {
85 return Err("Maximum code size cannot be zero".to_string());
86 }
87
88 if self.max_llm_calls_per_hour == 0 {
89 return Err("Maximum LLM calls per hour cannot be zero".to_string());
90 }
91
92 Ok(())
93 }
94
95 pub fn is_development(&self) -> bool {
97 !self.strict_mode && !self.enable_injection_detection
98 }
99
100 pub fn is_production(&self) -> bool {
102 self.strict_mode && self.enable_injection_detection
103 }
104
105 pub fn describe(&self) -> String {
107 format!(
108 "LLMSecurityConfig: injection_detection={}, output_validation={}, max_size={}B, strict={}, log_attacks={}, rate_limit={}/hour",
109 self.enable_injection_detection,
110 self.enable_output_validation,
111 self.max_code_size_bytes,
112 self.strict_mode,
113 self.log_attacks,
114 self.max_llm_calls_per_hour
115 )
116 }
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct InjectionDetectionResult {
122 pub is_malicious: bool,
124 pub confidence: f32,
126 pub detected_patterns: Vec<String>,
128 pub risk_score: u32,
130}
131
132impl InjectionDetectionResult {
133 pub fn new(is_malicious: bool, confidence: f32, detected_patterns: Vec<String>, risk_score: u32) -> Self {
135 Self {
136 is_malicious,
137 confidence,
138 detected_patterns,
139 risk_score,
140 }
141 }
142
143 pub fn safe() -> Self {
145 Self {
146 is_malicious: false,
147 confidence: 0.0,
148 detected_patterns: Vec::new(),
149 risk_score: 0,
150 }
151 }
152
153 pub fn malicious(confidence: f32, detected_patterns: Vec<String>, risk_score: u32) -> Self {
155 Self {
156 is_malicious: true,
157 confidence,
158 detected_patterns,
159 risk_score,
160 }
161 }
162
163 pub fn is_high_risk(&self) -> bool {
165 self.risk_score >= crate::constants::DEFAULT_HIGH_RISK_THRESHOLD
166 }
167
168 pub fn is_critical_risk(&self) -> bool {
170 self.risk_score >= crate::constants::REGEX_DOS_RISK_SCORE
171 }
172
173 pub fn risk_level(&self) -> &'static str {
175 if self.is_critical_risk() {
176 "CRITICAL"
177 } else if self.is_high_risk() {
178 "HIGH"
179 } else if self.risk_score >= crate::constants::DEFAULT_MALICIOUS_THRESHOLD {
180 "MEDIUM"
181 } else if self.risk_score > 0 {
182 "LOW"
183 } else {
184 "NONE"
185 }
186 }
187
188 pub fn summary(&self) -> String {
190 if self.is_malicious {
191 format!(
192 "MALICIOUS ({}): {} patterns detected, risk score: {}, confidence: {:.2}",
193 self.risk_level(),
194 self.detected_patterns.len(),
195 self.risk_score,
196 self.confidence
197 )
198 } else {
199 "SAFE: No malicious patterns detected".to_string()
200 }
201 }
202}
203
204pub struct LLMSecurity {
206 config: LLMSecurityConfig,
207}
208
209impl LLMSecurity {
210 pub fn new(config: LLMSecurityConfig) -> Self {
212 Self { config }
213 }
214
215 pub fn default() -> Self {
217 Self::new(LLMSecurityConfig::default())
218 }
219
220 pub fn config(&self) -> &LLMSecurityConfig {
222 &self.config
223 }
224
225 pub fn update_config(&mut self, config: LLMSecurityConfig) {
227 self.config = config;
228 }
229}