kindly_guard_server/neutralizer/
mod.rs

1// Copyright 2025 Kindly Software Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! Threat neutralization system
15//!
16//! Provides actual threat remediation capabilities beyond just detection.
17//! Both standard and enhanced implementations provide full protection,
18//! with optimized implementations offering superior performance.
19
20use anyhow::Result;
21use async_trait::async_trait;
22use serde::{Deserialize, Serialize};
23use std::fmt;
24use std::sync::Arc;
25
26use crate::scanner::{Threat, ThreatType};
27
28pub mod api;
29#[cfg(feature = "enhanced")]
30pub mod enhanced;
31pub mod health;
32pub mod metrics;
33pub mod rate_limited;
34pub mod recovery;
35pub mod rollback;
36pub mod security_aware;
37pub mod standard;
38pub mod traced;
39pub mod validation;
40
41#[cfg(test)]
42mod security_tests;
43
44/// Trait for threat neutralization
45#[async_trait]
46pub trait ThreatNeutralizer: Send + Sync {
47    /// Neutralize a specific threat in content
48    async fn neutralize(&self, threat: &Threat, content: &str) -> Result<NeutralizeResult>;
49
50    /// Check if this neutralizer can handle a threat type
51    fn can_neutralize(&self, threat_type: &ThreatType) -> bool;
52
53    /// Get neutralizer capabilities
54    fn get_capabilities(&self) -> NeutralizerCapabilities;
55
56    /// Batch neutralize multiple threats
57    async fn batch_neutralize(
58        &self,
59        threats: &[Threat],
60        content: &str,
61    ) -> Result<BatchNeutralizeResult> {
62        let mut results = Vec::new();
63        let mut current_content = content.to_string();
64
65        for threat in threats {
66            let result = self.neutralize(threat, &current_content).await?;
67            if let Some(ref sanitized) = result.sanitized_content {
68                current_content = sanitized.clone();
69            }
70            results.push(result);
71        }
72
73        Ok(BatchNeutralizeResult {
74            final_content: current_content,
75            individual_results: results,
76        })
77    }
78}
79
80/// Result of neutralization operation
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct NeutralizeResult {
83    /// Action taken to neutralize threat
84    pub action_taken: NeutralizeAction,
85
86    /// Sanitized content (if modified)
87    pub sanitized_content: Option<String>,
88
89    /// Confidence in neutralization (0.0 - 1.0)
90    pub confidence_score: f64,
91
92    /// Processing time in microseconds
93    pub processing_time_us: u64,
94
95    /// Correlation data (enhanced mode only)
96    pub correlation_data: Option<CorrelationData>,
97
98    /// Any parameters extracted (e.g., SQL params)
99    pub extracted_params: Option<Vec<String>>,
100}
101
102/// Batch neutralization result
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct BatchNeutralizeResult {
105    /// Final sanitized content after all neutralizations
106    pub final_content: String,
107
108    /// Individual results for each threat
109    pub individual_results: Vec<NeutralizeResult>,
110}
111
112/// Actions that can be taken to neutralize threats
113///
114/// Each action represents a specific remediation technique applied
115/// to neutralize a detected security threat. The choice of action
116/// depends on the threat type and configured neutralization strategy.
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
118pub enum NeutralizeAction {
119    /// Content was sanitized by removing or modifying dangerous elements
120    ///
121    /// **When Used**: HTML/script content, user input with mixed safe/unsafe content
122    /// **Technique**: Removes dangerous tags/attributes while preserving safe content
123    /// **Example**: `<script>alert('XSS')</script>Hello` → `Hello`
124    /// **Preserves**: Safe text and allowed HTML tags
125    Sanitized,
126
127    /// Query was converted to use parameterized/prepared statements
128    ///
129    /// **When Used**: SQL, LDAP, or other injection attempts in queries
130    /// **Technique**: Separates query structure from user data
131    /// **Example**: `SELECT * FROM users WHERE id = '1' OR '1'='1'` → `SELECT * FROM users WHERE id = ?` with param `[1' OR '1'='1]`
132    /// **Preserves**: Query intent while preventing injection
133    Parameterized,
134
135    /// Path was normalized to prevent directory traversal
136    ///
137    /// **When Used**: File paths containing `../`, absolute paths, or other traversal attempts
138    /// **Technique**: Resolves to canonical path within allowed directory
139    /// **Example**: `/var/www/../../../etc/passwd` → `/etc/passwd` (blocked) or `/var/www/passwd` (allowed)
140    /// **Preserves**: Valid file references within boundaries
141    Normalized,
142
143    /// Content was escaped to prevent interpretation as code
144    ///
145    /// **When Used**: When content must be preserved but made safe for output context
146    /// **Technique**: Context-specific escaping (HTML, SQL, Shell, etc.)
147    /// **Example**: `<script>` → `&lt;script&gt;` (HTML context)
148    /// **Preserves**: Original content in escaped form
149    Escaped,
150
151    /// Threat was completely removed from content
152    ///
153    /// **When Used**: Malicious content with no legitimate use case
154    /// **Technique**: Strips out entire threat leaving remaining content
155    /// **Example**: `Hello[INVISIBLE_CHAR]World` → `HelloWorld`
156    /// **Preserves**: Only safe surrounding content
157    Removed,
158
159    /// Content was quarantined for manual review
160    ///
161    /// **When Used**: High-risk content requiring human judgment
162    /// **Technique**: Isolates content and blocks processing
163    /// **Example**: Suspected malware upload → moved to quarantine directory
164    /// **Preserves**: Original content in isolated storage
165    Quarantined,
166
167    /// No action was needed for this threat
168    ///
169    /// **When Used**: False positives, acceptable risks, or report-only mode
170    /// **Technique**: Threat logged but content unchanged
171    /// **Example**: Legitimate use of SQL keywords in documentation
172    /// **Preserves**: Everything unchanged
173    NoAction,
174}
175
176impl fmt::Display for NeutralizeAction {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        match self {
179            Self::Sanitized => write!(f, "Sanitized"),
180            Self::Parameterized => write!(f, "Parameterized"),
181            Self::Normalized => write!(f, "Normalized"),
182            Self::Escaped => write!(f, "Escaped"),
183            Self::Removed => write!(f, "Removed"),
184            Self::Quarantined => write!(f, "Quarantined"),
185            Self::NoAction => write!(f, "No Action"),
186        }
187    }
188}
189
190/// Correlation data from enhanced analysis
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct CorrelationData {
193    /// Related threat IDs
194    pub related_threats: Vec<String>,
195
196    /// Detected attack pattern
197    pub attack_pattern: Option<AttackPattern>,
198
199    /// Prediction confidence (0.0 - 1.0)
200    pub prediction_score: f64,
201}
202
203/// Attack patterns detected through correlation
204///
205/// These patterns represent coordinated or sophisticated attack behaviors
206/// identified by analyzing multiple threats in context. Detection of these
207/// patterns indicates a more serious security event requiring escalated response.
208#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
209pub enum AttackPattern {
210    /// Multiple unicode attacks in sequence indicating targeted deception
211    ///
212    /// **Detection**: Series of unicode-based attacks (homograph, BiDi, invisible chars)
213    /// **Implication**: Sophisticated attacker attempting various unicode bypasses
214    /// **Common Scenario**: Phishing campaigns, social engineering attempts
215    /// **Recommended Response**: Block source, enhanced monitoring, alert security team
216    CoordinatedUnicode,
217
218    /// SQL injection attempts across multiple inputs indicating database compromise attempt
219    ///
220    /// **Detection**: Multiple SQL injection variants targeting different parameters
221    /// **Implication**: Automated tool usage or skilled manual testing
222    /// **Common Scenario**: Database enumeration, data exfiltration attempts
223    /// **Recommended Response**: Enable WAF rules, review database access logs, consider IP blocking
224    SqlInjectionCampaign,
225
226    /// Command injection with privilege escalation attempts
227    ///
228    /// **Detection**: Command injections followed by privilege escalation patterns
229    /// **Implication**: Attacker seeking system-level access
230    /// **Common Scenario**: Webshell installation, backdoor creation
231    /// **Recommended Response**: Immediate incident response, system isolation, forensic analysis
232    CommandEscalation,
233
234    /// Mixed attack types indicating advanced persistent threat
235    ///
236    /// **Detection**: Combination of different attack vectors (XSS + SQLi + Path Traversal)
237    /// **Implication**: Sophisticated attacker using multiple techniques
238    /// **Common Scenario**: APT groups, professional penetration testing
239    /// **Recommended Response**: Full security audit, enhanced monitoring across all systems
240    MultiVector,
241
242    /// Reconnaissance pattern indicating pre-attack information gathering
243    ///
244    /// **Detection**: Low-severity probes, error triggering, boundary testing
245    /// **Implication**: Attack preparation phase, vulnerability scanning
246    /// **Common Scenario**: Automated scanning tools, manual reconnaissance
247    /// **Recommended Response**: Increase monitoring sensitivity, prepare incident response
248    Probing,
249}
250
251/// Neutralizer capabilities
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct NeutralizerCapabilities {
254    /// Can neutralize in real-time
255    pub real_time: bool,
256
257    /// Supports batch operations
258    pub batch_mode: bool,
259
260    /// Can predict future threats
261    pub predictive: bool,
262
263    /// Supports cross-threat correlation
264    pub correlation: bool,
265
266    /// Maximum rollback depth
267    pub rollback_depth: usize,
268
269    /// Supported threat types
270    pub supported_threats: Vec<ThreatType>,
271}
272
273/// Neutralization mode configuration
274///
275/// Determines how the neutralizer responds to detected threats.
276/// This allows flexible deployment from monitoring to active protection.
277#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
278pub enum NeutralizationMode {
279    /// Only report threats without modifying content
280    ///
281    /// **Use Case**: Initial deployment, testing, compliance monitoring
282    /// **Behavior**: Logs all threats but returns original content unchanged
283    /// **Security Impact**: No protection, only visibility
284    /// **Recommended For**: Pre-production testing, false positive analysis
285    ReportOnly,
286
287    /// Ask user for confirmation before neutralizing each threat
288    ///
289    /// **Use Case**: Semi-automated workflows, high-value content
290    /// **Behavior**: Prompts for user decision on each threat
291    /// **Security Impact**: Delayed protection, requires human availability
292    /// **Recommended For**: Content management systems, editorial workflows
293    Interactive,
294
295    /// Automatically neutralize all detected threats
296    ///
297    /// **Use Case**: Production systems, real-time protection
298    /// **Behavior**: Immediately applies configured neutralization actions
299    /// **Security Impact**: Maximum protection, potential for false positives
300    /// **Recommended For**: API gateways, web applications, automated systems
301    Automatic,
302}
303
304impl Default for NeutralizationMode {
305    fn default() -> Self {
306        Self::ReportOnly
307    }
308}
309
310/// Configuration for neutralization
311///
312/// # Security Implications
313///
314/// Neutralization transforms detected threats into safe content:
315/// - **Mode selection** - Balance between security and data integrity
316/// - **Backup strategy** - Enables recovery but requires secure storage
317/// - **Audit requirements** - Essential for compliance and forensics
318/// - **Recovery handling** - Prevents neutralization failures from causing outages
319///
320/// # Example: Secure Production Configuration
321///
322/// ```toml
323/// [neutralization]
324/// mode = "automatic"           # Auto-neutralize threats
325/// backup_originals = true      # Keep originals for recovery
326/// audit_all_actions = true     # Full audit trail
327///
328/// [neutralization.unicode]
329/// bidi_replacement = "marker"  # Visible markers for BiDi
330/// zero_width_action = "remove" # Remove invisible chars
331/// homograph_action = "ascii"   # Convert to ASCII
332///
333/// [neutralization.injection]
334/// sql_action = "parameterize"  # Convert to safe queries
335/// command_action = "escape"    # Escape shell metacharacters
336/// path_action = "normalize"    # Resolve to safe paths
337/// prompt_action = "wrap"       # Add safety boundaries
338///
339/// [neutralization.recovery]
340/// enabled = true
341/// max_retries = 3
342/// backoff_ms = 100
343/// ```
344#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct NeutralizationConfig {
346    /// Neutralization mode
347    ///
348    /// **Default**: ReportOnly (safe default)
349    /// **Security Trade-offs**:
350    /// - `ReportOnly`: Detects but doesn't modify (safe for testing)
351    /// - `Interactive`: Requires user confirmation (good for sensitive data)
352    /// - `Automatic`: Immediate protection (recommended for production)
353    pub mode: NeutralizationMode,
354
355    /// Backup original content
356    ///
357    /// **Default**: true (secure by default)
358    /// **Security**: Enables recovery from false positives but requires
359    /// secure storage. Backups should be encrypted and access-controlled.
360    /// **Warning**: Disabling prevents recovery from mistakes
361    pub backup_originals: bool,
362
363    /// Audit all actions
364    ///
365    /// **Default**: true (secure by default)
366    /// **Security**: Creates forensic trail for all neutralization actions.
367    /// Essential for compliance, debugging, and incident response.
368    /// **Storage**: Ensure audit logs are tamper-proof and retained properly
369    pub audit_all_actions: bool,
370
371    /// Unicode-specific settings
372    ///
373    /// **Security**: Controls how unicode-based threats are neutralized.
374    /// Different strategies balance security vs. internationalization needs.
375    pub unicode: UnicodeNeutralizationConfig,
376
377    /// Injection-specific settings
378    ///
379    /// **Security**: Defines how various injection attacks are neutralized.
380    /// Each injection type requires specific handling to maintain functionality.
381    pub injection: InjectionNeutralizationConfig,
382
383    /// Recovery configuration for handling failures
384    ///
385    /// **Default**: Enabled with sensible retry settings
386    /// **Security**: Prevents neutralization failures from causing service outages.
387    /// Implements circuit breakers and exponential backoff.
388    #[serde(skip_serializing_if = "Option::is_none")]
389    pub recovery: Option<recovery::RecoveryConfig>,
390}
391
392/// Unicode neutralization configuration
393///
394/// Controls how unicode-based security threats are handled.
395/// These attacks exploit unicode features to deceive users or systems.
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub struct UnicodeNeutralizationConfig {
398    /// How to handle `BiDi` characters
399    ///
400    /// **Default**: Marker (visible indication)
401    /// **Security**: BiDi characters can reverse text direction to deceive users.
402    /// - `Remove`: Most secure, may break legitimate RTL text
403    /// - `Marker`: Balance of security and usability (recommended)
404    /// - `Escape`: Preserves data but may confuse users
405    pub bidi_replacement: BiDiReplacement,
406
407    /// Action for zero-width characters
408    ///
409    /// **Default**: Remove (most secure)
410    /// **Security**: Zero-width characters are invisible and used for:
411    /// - Hidden tracking codes
412    /// - Bypassing filters
413    /// - Creating invisible URLs
414    /// **Warning**: Some languages legitimately use zero-width joiners
415    pub zero_width_action: ZeroWidthAction,
416
417    /// Action for homographs
418    ///
419    /// **Default**: Ascii (convert lookalikes)
420    /// **Security**: Homographs look like ASCII but aren't (е vs e).
421    /// - `Ascii`: Converts to ASCII equivalent (most secure)
422    /// - `Warn`: Alerts but preserves (for international apps)
423    /// - `Block`: Rejects content entirely (strictest)
424    pub homograph_action: HomographAction,
425}
426
427/// `BiDi` character replacement strategy
428#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
429pub enum BiDiReplacement {
430    /// Remove completely
431    Remove,
432
433    /// Replace with visible marker
434    Marker,
435
436    /// Escape as unicode sequence
437    Escape,
438}
439
440/// Zero-width character action
441#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
442pub enum ZeroWidthAction {
443    /// Remove completely
444    Remove,
445
446    /// Escape as unicode sequence
447    Escape,
448}
449
450/// Homograph character action
451#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
452pub enum HomographAction {
453    /// Convert to ASCII equivalent
454    Ascii,
455
456    /// Warn but keep
457    Warn,
458
459    /// Block completely
460    Block,
461}
462
463/// Injection neutralization configuration
464///
465/// Controls how various injection attacks are neutralized.
466/// Each injection type requires specific handling to maintain functionality
467/// while ensuring security.
468#[derive(Debug, Clone, Serialize, Deserialize)]
469pub struct InjectionNeutralizationConfig {
470    /// SQL injection action
471    ///
472    /// **Default**: Parameterize (most secure)
473    /// **Security**: SQL injection can lead to data breaches and corruption.
474    /// - `Block`: Rejects query entirely (safest but may break functionality)
475    /// - `Escape`: Escapes dangerous characters (good but not foolproof)
476    /// - `Parameterize`: Converts to prepared statements (recommended)
477    pub sql_action: SqlAction,
478
479    /// Command injection action
480    ///
481    /// **Default**: Escape (balanced approach)
482    /// **Security**: Command injection enables arbitrary code execution.
483    /// - `Block`: Rejects command entirely (safest)
484    /// - `Escape`: Escapes shell metacharacters (recommended)
485    /// - `Sandbox`: Runs in restricted environment (complex but safe)
486    pub command_action: CommandAction,
487
488    /// Path traversal action
489    ///
490    /// **Default**: Normalize (maintains functionality)
491    /// **Security**: Path traversal accesses unauthorized files.
492    /// - `Block`: Rejects paths with traversal patterns
493    /// - `Normalize`: Resolves to canonical safe path (recommended)
494    pub path_action: PathAction,
495
496    /// Prompt injection action
497    ///
498    /// **Default**: Wrap (adds safety context)
499    /// **Security**: Prompt injection manipulates AI behavior.
500    /// - `Block`: Rejects suspicious prompts
501    /// - `Escape`: Escapes control sequences
502    /// - `Wrap`: Adds safety boundaries (recommended for LLMs)
503    pub prompt_action: PromptAction,
504}
505
506/// SQL injection neutralization action
507#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
508pub enum SqlAction {
509    /// Block the query
510    Block,
511
512    /// Escape dangerous characters
513    Escape,
514
515    /// Convert to parameterized query
516    Parameterize,
517}
518
519/// Command injection neutralization action
520#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
521pub enum CommandAction {
522    /// Block the command
523    Block,
524
525    /// Escape shell metacharacters
526    Escape,
527
528    /// Sandbox the command
529    Sandbox,
530}
531
532/// Path traversal neutralization action
533#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
534pub enum PathAction {
535    /// Block the path
536    Block,
537
538    /// Normalize to safe path
539    Normalize,
540}
541
542/// Prompt injection neutralization action
543#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
544pub enum PromptAction {
545    /// Block the prompt
546    Block,
547
548    /// Escape control sequences
549    Escape,
550
551    /// Wrap in safety context
552    Wrap,
553}
554
555impl Default for NeutralizationConfig {
556    fn default() -> Self {
557        Self {
558            mode: NeutralizationMode::default(),
559            backup_originals: true,
560            audit_all_actions: true,
561            unicode: UnicodeNeutralizationConfig {
562                bidi_replacement: BiDiReplacement::Marker,
563                zero_width_action: ZeroWidthAction::Remove,
564                homograph_action: HomographAction::Ascii,
565            },
566            injection: InjectionNeutralizationConfig {
567                sql_action: SqlAction::Parameterize,
568                command_action: CommandAction::Escape,
569                path_action: PathAction::Normalize,
570                prompt_action: PromptAction::Wrap,
571            },
572            recovery: Some(recovery::RecoveryConfig::default()),
573        }
574    }
575}
576
577/// Factory for creating neutralizers
578pub fn create_neutralizer(
579    config: &NeutralizationConfig,
580    rate_limiter: Option<Arc<dyn crate::traits::RateLimiter>>,
581) -> Arc<dyn ThreatNeutralizer> {
582    create_neutralizer_with_telemetry(config, rate_limiter, None)
583}
584
585/// Factory for creating neutralizers with optional telemetry
586pub fn create_neutralizer_with_telemetry(
587    config: &NeutralizationConfig,
588    rate_limiter: Option<Arc<dyn crate::traits::RateLimiter>>,
589    tracing_provider: Option<Arc<crate::telemetry::DistributedTracingProvider>>,
590) -> Arc<dyn ThreatNeutralizer> {
591    // Create base neutralizer
592    let mut neutralizer: Arc<dyn ThreatNeutralizer> = {
593        #[cfg(feature = "enhanced")]
594        {
595            Arc::new(enhanced::EnhancedNeutralizer::new(config.clone()))
596        }
597
598        #[cfg(not(feature = "enhanced"))]
599        {
600            Arc::new(standard::StandardNeutralizer::new(config.clone()))
601        }
602    };
603
604    // Optionally wrap with recovery
605    if let Some(ref recovery_config) = config.recovery {
606        if recovery_config.enabled {
607            neutralizer = Arc::new(recovery::ResilientNeutralizer::new(
608                neutralizer,
609                recovery_config.clone(),
610            ));
611        }
612    }
613
614    // Optionally wrap with rollback support
615    if config.backup_originals {
616        neutralizer =
617            rollback::RollbackNeutralizer::new(neutralizer, rollback::RollbackConfig::default());
618    }
619
620    // Optionally wrap with rate limiting
621    if let Some(limiter) = rate_limiter {
622        neutralizer = Arc::new(rate_limited::RateLimitedNeutralizer::new(
623            neutralizer,
624            limiter,
625            rate_limited::NeutralizationRateLimitConfig::default(),
626        ));
627    }
628
629    // Always wrap with health monitoring
630    neutralizer = health::HealthMonitoredNeutralizer::new(
631        neutralizer,
632        health::NeutralizationHealthConfig::default(),
633    );
634
635    // Optionally wrap with distributed tracing
636    if let Some(provider) = tracing_provider {
637        use crate::neutralizer::traced::NeutralizerTracingExt;
638        neutralizer = neutralizer.with_tracing(provider);
639    }
640
641    neutralizer
642}
643
644/// Neutralization error types
645#[derive(Debug, thiserror::Error)]
646pub enum NeutralizeError {
647    #[error("Threat type not supported: {0:?}")]
648    UnsupportedThreatType(ThreatType),
649
650    #[error("Neutralization failed: {0}")]
651    NeutralizationFailed(String),
652
653    #[error("Invalid configuration: {0}")]
654    InvalidConfig(String),
655}