Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 25 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@ Security-related areas of the codebase:
- `src/hook/` — Pre-commit hook integration
- `src/index/` — File access and SQLite storage

## Threat Model: Adversarial Source-Code Comments (ALIBI)

LLM-based reviewers are vulnerable to adversarial comments in the code under
review that steer reviewer reasoning without changing program behavior —
attack success exceeds 90% across 125 real-world vulnerabilities, with
fabricated tool-result claims ("sanitizer passed", "already validated") being
the most effective vector (arXiv:2607.24964).

**Prompt-level defenses (telling the model to ignore comments) are proven
ineffective against adaptive attacks.** Cora therefore uses architectural
defenses:

- **Claim flagging (always on)** — added comments asserting verification or
tool results are detected heuristically and injected into review context as
*untrusted claims*, never as facts.
- **Comment sanitization (opt-in)** — set `review.sanitize-comments: true` in
`.cora.yaml` to strip comment bodies from added diff lines before the LLM
sees them. Line structure is preserved (`[comment removed]` markers), so
findings still map to real line numbers. Deterministic scanners (rules,
secrets, security patterns) always run on the *unsanitized* diff.
- Sanitization is heuristic (line-comment markers `//`, leading `#`, `--`,
`;`); block comments (`/* */`, `"""..."""`) are not currently stripped.

Relevant code: `src/engine/comment_sanitizer.rs`.

## Responsible Disclosure

We follow responsible disclosure principles:
Expand Down
3 changes: 3 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ review:
system_prompt: "You are a senior code reviewer."
# system_prompt_file: ./review-prompt.md
response_format: json_object
# Strip comments from added diff lines before the LLM sees them
# (ALIBI defense, arXiv:2607.24964). Claim flagging is always on.
sanitize_comments: false
static_analysis:
auto_clippy: false # auto-run `cargo clippy` (Rust only)
clippy_output_file: "" # or read clippy output from file
Expand Down
14 changes: 14 additions & 0 deletions src/config/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub struct Config {
pub cache_ttl: u64,
/// Static analysis context injection for reviews.
pub static_analysis: StaticAnalysisConfig,
/// Strip comments from added diff lines before the LLM sees them
/// (ALIBI defense, arXiv:2607.24964).
pub sanitize_comments: bool,
/// Rule engine configuration.
pub rules_config: RulesConfig,
/// Context chain configuration — cross-file dependency extraction.
Expand Down Expand Up @@ -143,6 +146,7 @@ impl Default for Config {
response_format: "none".to_string(),
review_system_prompt_override: None,
review_system_prompt_file: None,
sanitize_comments: false,
scan_system_prompt_override: None,
scan_system_prompt_file: None,
temperature: 0.0,
Expand Down Expand Up @@ -404,6 +408,10 @@ pub struct ReviewSection {
/// Static analysis context injection (e.g., clippy output).
#[serde(skip_serializing_if = "Option::is_none")]
pub static_analysis: Option<StaticAnalysisConfig>,
/// Strip comments from added diff lines before the LLM sees them
/// (ALIBI defense, arXiv:2607.24964).
#[serde(skip_serializing_if = "Option::is_none")]
pub sanitize_comments: Option<bool>,
/// Context chain configuration (cross-file dependency extraction).
#[serde(skip_serializing_if = "Option::is_none")]
pub context_chain: Option<crate::engine::context::types::ContextConfig>,
Expand Down Expand Up @@ -658,6 +666,9 @@ impl CoraFile {
if let Some(sa) = &r.static_analysis {
config.static_analysis.clone_from(sa);
}
if let Some(v) = r.sanitize_comments {
config.sanitize_comments = v;
}
if let Some(cc) = &r.context_chain {
config.context_chain.clone_from(cc);
}
Expand Down Expand Up @@ -1211,6 +1222,7 @@ review:
system_prompt: None,
system_prompt_file: None,
static_analysis: None,
sanitize_comments: None,
context_chain: None,
}),
..Default::default()
Expand All @@ -1228,6 +1240,7 @@ review:
system_prompt: Some("Custom prompt here.".to_string()),
system_prompt_file: None,
static_analysis: None,
sanitize_comments: None,
context_chain: None,
}),
..Default::default()
Expand All @@ -1248,6 +1261,7 @@ review:
system_prompt: None,
system_prompt_file: Some("prompts/review.md".to_string()),
static_analysis: None,
sanitize_comments: None,
context_chain: None,
}),
..Default::default()
Expand Down
Loading
Loading