Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions crates/goose/src/security/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
pub explanation: String,
}

#[derive(Clone)]
struct DetailedScanResult {
confidence: f32,
pattern_matches: Vec<PatternMatch>,
Expand Down Expand Up @@ -106,20 +107,23 @@
self.scan_conversation(messages)
);

let highest_confidence_result =
self.select_highest_confidence_result(tool_result?, context_result?);
let tool_result = tool_result?;
let context_result = context_result?;
let threshold = self.get_threshold_from_config();

let final_result =
self.select_result_with_context_awareness(tool_result, context_result, threshold);

tracing::info!(
"Security analysis complete: confidence={:.3}, malicious={}",
highest_confidence_result.confidence,
highest_confidence_result.confidence >= threshold
"Security analysis complete: confidence={:.3}, malicious={}",
final_result.confidence,
final_result.confidence >= threshold
);

Ok(ScanResult {
is_malicious: highest_confidence_result.confidence >= threshold,
confidence: highest_confidence_result.confidence,
explanation: self.build_explanation(&highest_confidence_result, threshold),
is_malicious: final_result.confidence >= threshold,
confidence: final_result.confidence,
explanation: self.build_explanation(&final_result, threshold),
})
}

Expand Down Expand Up @@ -169,12 +173,39 @@
})
}

fn select_highest_confidence_result(
fn select_result_with_context_awareness(
&self,
tool_result: DetailedScanResult,
context_result: DetailedScanResult,
threshold: f32,
) -> DetailedScanResult {
if tool_result.confidence >= context_result.confidence {
let context_is_safe = context_result
.ml_confidence
.is_some_and(|conf| conf < threshold);

let tool_has_only_non_critical = !tool_result.pattern_matches.is_empty()
&& tool_result
.pattern_matches
.iter()
.all(|m| m.threat.risk_level != crate::security::patterns::RiskLevel::Critical);

Check warning on line 190 in crates/goose/src/security/scanner.rs

View workflow job for this annotation

GitHub Actions / Check Rust Code Format

Diff in /home/runner/work/goose/goose/crates/goose/src/security/scanner.rs

if context_is_safe && tool_has_only_non_critical {
tracing::info!(
"Suppressing non-critical pattern match due to safe context evaluation"
);
tracing::debug!(
context_ml_confidence = ?context_result.ml_confidence,
pattern_count = tool_result.pattern_matches.len(),
max_pattern_risk = ?tool_result.pattern_matches.first().map(|m| &m.threat.risk_level),
"Suppression conditions met: safe context + non-critical patterns"
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you want to info & debug log here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, this was helpful for local testing but can probably get rid of these for now, ty!


DetailedScanResult {
confidence: 0.0,
pattern_matches: Vec::new(),
ml_confidence: context_result.ml_confidence,
}
Comment on lines +208 to +213

Copilot AI Jan 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new suppression logic lacks test coverage. Add a test that verifies the behavior when context is safe (low ML confidence) and the tool result contains only non-critical pattern matches to ensure the suppression works as intended.

Copilot uses AI. Check for mistakes.
} else if tool_result.confidence >= context_result.confidence {
Comment on lines +208 to +214

Copilot AI Jan 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppression only checks pattern risk levels but ignores ML confidence from the tool scan. If tool_result has high ML confidence with non-Critical patterns, it will be suppressed despite the ML model flagging the tool content as malicious. Add a check: tool_result.ml_confidence is None or below threshold before suppressing.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the entire point of the PR? Maybe i'm misunderstanding copilot, but the idea is to reduce false positives for the time being and generally increase sensitivity again later on. Same goes for comment below

tool_result
} else {
context_result
Expand Down
Loading