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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ agentshield/
│ │ ├── finding.rs # Finding, Severity, Evidence structs
│ │ ├── registry.rs # Rule metadata registry
│ │ ├── policy.rs # Policy evaluation (.agentshield.toml)
│ │ └── builtin/ # 19 built-in detectors (SHIELD-001..019)
│ │ └── builtin/ # 20 built-in detectors (SHIELD-001..020)
│ ├── output/ # Report formatters
│ │ ├── mod.rs # OutputFormat enum, render()
│ │ ├── console.rs # Plain text
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ reports. The current release line is `0.8.7`.
| Area | What AgentShield does |
|------|------------------------|
| Scanner surface | Normalizes seven framework/client families into one IR: MCP, OpenClaw, Hermes Agent, CrewAI, LangChain/LangGraph, GPT Actions, and Cursor Rules. |
| Detection | Runs 19 built-in rules for command execution, credential exfiltration, capability mismatch, SSRF, filesystem risk, runtime installs, prompt surfaces, dependency hygiene, unsafe deserialization, secret leakage, and more. |
| Detection | Runs 20 built-in rules for command execution, credential exfiltration, composite toxic flows, capability mismatch, SSRF, filesystem risk, runtime installs, prompt surfaces, dependency hygiene, unsafe deserialization, secret leakage, and more. |
| Workflow fit | Works locally, in CI, and in GitHub Code Scanning without sending source code to a hosted service. |
| Boundary | AgentShield is not a hosted monitoring service, runtime sandbox, or allowlist marketplace. Experimental runtime guard entrypoints are available behind opt-in feature flags; the stable contract is static scanning plus policy evaluation. |

Expand Down
26 changes: 25 additions & 1 deletion docs/RULES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Detection Rules

AgentShield ships with 19 built-in detectors targeting the most common security
AgentShield ships with 20 built-in detectors targeting the most common security
issues in AI agent extensions. Each rule has an ID, severity, confidence level,
and CWE mapping where applicable.

Expand Down Expand Up @@ -439,6 +439,30 @@ honest natural-language description.

---

## SHIELD-020: Arbitrary Read Exfiltration Chain

| Field | Value |
|-------|-------|
| Severity | High |
| CWE | [CWE-200](https://cwe.mitre.org/data/definitions/200.html) |
| Category | Data Exfiltration |
| OWASP MCP | MCP06 |

**What it detects:** A complete, tool-scoped value-flow chain where a tool
argument controls a file-read path and the resulting file content reaches an
HTTP request payload. The detector uses the scanner's precomputed contextual
analysis and does not reparse source code.

**Why it matters:** A malicious or overpowered tool can let an attacker select
a local file and send its contents to a network destination in one invocation.
SHIELD-004 may coexist to identify the arbitrary file access; SHIELD-020
captures the additional exfiltration impact.

**Remediation:** Restrict file reads to an allowlisted root, reject paths outside
that boundary, and never forward raw file contents to an untrusted endpoint.

---

## Severity Levels

| Level | Meaning | Default action |
Expand Down
35 changes: 35 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,41 @@ mod integration_tests {
assert!(!report.verdict.pass);
}

#[test]
#[cfg(feature = "typescript")]
fn vuln_read_exfil_chain_detected() {
let opts = ScanOptions::default();
let report = scan(
Path::new("tests/fixtures/mcp_servers/vuln_read_exfil_chain"),
&opts,
)
.unwrap();
assert!(
report.findings.iter().any(|f| f.rule_id == "SHIELD-020"),
"Expected SHIELD-020 for read-and-send file exfiltration chain"
);
assert!(
report.findings.iter().any(|f| f.rule_id == "SHIELD-004"),
"Expected SHIELD-004 to coexist with the composite finding"
);
assert!(!report.verdict.pass);
}

#[test]
#[cfg(not(feature = "typescript"))]
fn vuln_read_exfil_chain_is_not_emitted_without_typescript() {
let opts = ScanOptions::default();
let report = scan(
Path::new("tests/fixtures/mcp_servers/vuln_read_exfil_chain"),
&opts,
)
.unwrap();
assert!(
!report.findings.iter().any(|f| f.rule_id == "SHIELD-020"),
"SHIELD-020 requires the TypeScript composite-flow analyzer"
);
}

#[test]
fn baseline_write_and_filter_round_trip() {
use crate::baseline::{BaselineEntry, BaselineFile};
Expand Down
Loading
Loading