1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! # `agentsec-core` — AgentSec pure-logic library
//!
//! Pure-Rust logic crate. No rmcp / clap / GUI dependency — the umbrella
//! binary `agentsec` is the only transport adapter (see the `agentsec`
//! crate for CLI / MCP server / hook wiring).
//!
//! This crate doc is the single source of truth for the threat model,
//! module roster, and read-only invariants. Module-level docs reference
//! the sections below by anchor (e.g. *crate root §Threat surface × vector*).
//!
//! ---
//!
//! ## §Threat surface × vector
//!
//! Defense is framed as a 2-axis matrix. The vertical axis is **where**
//! the threat is observed, the horizontal axis is **how** the injection
//! arrives. Modules cover the following cells:
//!
//! | Surface | Vector | Module |
//! |----------------------|----------------------|---------------|
//! | L1 Agent config dir | V3 Config tampering | [`scan`] |
//! | L4 Network egress | V1 Prompt injection | [`web`] |
//! | L5 User-facing input | V1 Prompt injection | [`paste`] |
//!
//! Surface key:
//!
//! - **L1 Agent config** — `~/.claude/`, `~/.cursor/`, `.mcp.json`, skills /
//! agents / plugins dirs, dependency manifests, lockfiles, `.env`
//! - **L2 Dependency manifest** — `package.json`, `Cargo.toml`, lockfiles
//! (covered by [`scan`] as a sub-axis of L1)
//! - **L3 Runtime process** — Agent / MCP subprocess (not implemented)
//! - **L4 Network egress** — outbound URL fetch from Agent context
//! - **L5 User-facing input** — pasted text, prompt body, tool args
//!
//! Vector key:
//!
//! - **V1 Prompt injection** — instruction-override text in fetched URL / RAG
//! / pasted content
//! - **V2 Supply chain** — typosquat / hijacked package (not implemented)
//! - **V3 Config tampering** — newly-installed / mutated config under L1
//! - **V4 Runtime tampering** — process injection (not implemented)
//!
//! ## §Module roster
//!
//! | Module path | Role |
//! |--------------------|---------------------------------------------------|
//! | [`scan`] | Hash inventory of agent config + lockfiles; diff against the previous snapshot. |
//! | [`paste`] | Multi-layer decode + multi-pattern scan + unicode anomaly check; verdict Clean / Suspicious / Blocked. |
//! | [`web`] | URL fetch with body cap + 2-layer sanitize (regex then optional LLM) + `<untrusted_content>` envelope. |
//! | [`output`] | Render a [`scan::ScanOutcome`] as Markdown. |
//! | [`registry`] | Known-good MCP server registry (builtin + cache + net fetch). |
//! | [`plain_mode`] | Temporarily disable `.mcp.json` files via rename + stub. |
//! | [`emergency_stop`] | Enumerate Agent / MCP processes by name and SIGTERM them. |
//! | [`config`] | Edge-resolved `Config` (env → struct); the only env-reading code. |
//! | [`error`] | Crate-wide error enum. |
//!
//! ## §Runtime data root
//!
//! All persisted state lives under [`config::Paths::home`], resolved at
//! the binary's outer rim by [`config::Config::from_env`] as:
//!
//! 1. `$AGENTSEC_HOME` if set (used by integration tests to redirect to a
//! tempdir), else
//! 2. `$HOME/.agentsec/`, else
//! 3. `./.agentsec/` (last-resort fallback when `HOME` is unset).
//!
//! Layout:
//!
//! ```text
//! <home>/snapshots/<UTC-ts>.json — scan snapshots (scan::snapshot)
//! <home>/scans/last-session-start.txt — last SessionStart hook summary
//! <home>/paste_log/<UTC-ts>-<id>.json — paste verdicts
//! <home>/web_log/<UTC-ts>-<id>.json — sanitize results
//! ```
//!
//! ## §Environment variables
//!
//! All env reads are funneled through [`config::Config::from_env`] (the
//! *only* function in this crate that touches `std::env`). Library
//! functions take `&Config` (or sub-references) as a parameter; they do
//! not consult the process environment at the point of use. See
//! [`config`] for the full mapping and the test-friendly
//! [`config::Config::from_env_lookup`] override.
//!
//! ## §Read-only invariants
//!
//! - [`scan`] never mutates any scanned path; it only reads bytes and writes
//! to `<home>/snapshots/`.
//! - [`paste`] never persists the raw input plaintext outside the JSON audit
//! row under `<home>/paste_log/`.
//! - [`web::fetch`] enforces a 2 MiB body cap and 15 s timeout; oversized
//! bodies are rejected, not truncated.
//! - [`web::sanitize::semantic_layer`] **fails open**: a missing API key or
//! non-2xx response returns the regex-stripped input unchanged. The 1st
//! (regex) layer alone is the floor of protection.
//! - Symbolic links are not followed during [`scan::inventory::collect`].
pub use ;
pub use Error;