agentfort 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. agentfort-0.1.1/LICENSE +21 -0
  2. agentfort-0.1.1/PKG-INFO +154 -0
  3. agentfort-0.1.1/README.md +125 -0
  4. agentfort-0.1.1/agentfort.egg-info/PKG-INFO +154 -0
  5. agentfort-0.1.1/agentfort.egg-info/SOURCES.txt +37 -0
  6. agentfort-0.1.1/agentfort.egg-info/dependency_links.txt +1 -0
  7. agentfort-0.1.1/agentfort.egg-info/entry_points.txt +2 -0
  8. agentfort-0.1.1/agentfort.egg-info/requires.txt +6 -0
  9. agentfort-0.1.1/agentfort.egg-info/top_level.txt +1 -0
  10. agentfort-0.1.1/agentsentry/__init__.py +0 -0
  11. agentfort-0.1.1/agentsentry/cli.py +173 -0
  12. agentfort-0.1.1/agentsentry/db/__init__.py +0 -0
  13. agentfort-0.1.1/agentsentry/db/advisory.py +51 -0
  14. agentfort-0.1.1/agentsentry/db/data/AGSA-001.yaml +29 -0
  15. agentfort-0.1.1/agentsentry/db/data/AGSA-002.yaml +24 -0
  16. agentfort-0.1.1/agentsentry/db/data/AGSA-003.yaml +23 -0
  17. agentfort-0.1.1/agentsentry/db/data/AGSA-004.yaml +32 -0
  18. agentfort-0.1.1/agentsentry/db/data/AGSA-005.yaml +31 -0
  19. agentfort-0.1.1/agentsentry/db/data/AGSA-006.yaml +23 -0
  20. agentfort-0.1.1/agentsentry/db/data/AGSA-007.yaml +25 -0
  21. agentfort-0.1.1/agentsentry/db/data/AGSA-008.yaml +23 -0
  22. agentfort-0.1.1/agentsentry/db/data/AGSA-009.yaml +24 -0
  23. agentfort-0.1.1/agentsentry/db/data/AGSA-010.yaml +30 -0
  24. agentfort-0.1.1/agentsentry/db/data/AGSA-012.yaml +26 -0
  25. agentfort-0.1.1/agentsentry/db/data/AGSA-013.yaml +29 -0
  26. agentfort-0.1.1/agentsentry/db/data/AGSA-014.yaml +24 -0
  27. agentfort-0.1.1/agentsentry/db/data/AGSA-015.yaml +30 -0
  28. agentfort-0.1.1/agentsentry/models.py +54 -0
  29. agentfort-0.1.1/agentsentry/report/__init__.py +0 -0
  30. agentfort-0.1.1/agentsentry/report/formatter.py +145 -0
  31. agentfort-0.1.1/agentsentry/scanner/__init__.py +0 -0
  32. agentfort-0.1.1/agentsentry/scanner/frameworks.py +168 -0
  33. agentfort-0.1.1/agentsentry/scanner/mcp.py +153 -0
  34. agentfort-0.1.1/agentsentry/scanner/osv.py +117 -0
  35. agentfort-0.1.1/agentsentry/scanner/patterns.py +129 -0
  36. agentfort-0.1.1/agentsentry/scanner/secrets.py +71 -0
  37. agentfort-0.1.1/pyproject.toml +51 -0
  38. agentfort-0.1.1/setup.cfg +4 -0
  39. agentfort-0.1.1/tests/test_scanners.py +199 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NeuronKnight
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentfort
3
+ Version: 0.1.1
4
+ Summary: CVE-style advisory database and static scanner for AI agent security risks
5
+ Author-email: NeuronKnight <dev@neuronknight.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/NeuronKnight/agentfort
8
+ Project-URL: Source, https://github.com/NeuronKnight/agentfort
9
+ Project-URL: Issues, https://github.com/NeuronKnight/agentfort/issues
10
+ Keywords: security,ai,agents,mcp,llm,scanner,langchain,crewai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: click>=8.0
24
+ Requires-Dist: rich>=13.0
25
+ Requires-Dist: pyyaml>=6.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # AgentFort
31
+
32
+ Static security scanner for AI agent codebases. Analyzes repositories and MCP config files against a CVE-style advisory database — no live agent interaction required.
33
+
34
+ ## What it does
35
+
36
+ - Scans Python repos for dangerous patterns: `eval()`, `exec()`, `shell=True`, hardcoded API keys
37
+ - Parses MCP config files (`claude_desktop_config.json`, `.mcp.json`) for shell execution tools, overly broad filesystem access, and unverified `npx`/`uvx` packages
38
+ - Detects agent framework imports (LangChain, CrewAI, AutoGen, OpenAI, Anthropic, etc.) and cross-references against known vulnerabilities
39
+ - **Queries OSV.dev live** for real CVEs against every detected package — findings stay current without any database updates
40
+ - Produces risk scores, terminal reports, Markdown, and JSON output
41
+ - Exits with code 1 on critical findings — CI pipeline friendly
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ # From repo root (inside a virtualenv)
47
+ pip install agentfort
48
+
49
+ # Or dev install from repo
50
+ pip install -e agentsentry/
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ```bash
56
+ # Scan a repo
57
+ agentfort scan --repo /path/to/your/agent-project
58
+
59
+ # Scan just an MCP config file
60
+ agentfort scan --mcp-config ~/.config/claude/claude_desktop_config.json
61
+
62
+ # JSON output (clean stdout, progress on stderr)
63
+ agentfort scan --repo . --format json
64
+
65
+ # Markdown report to file
66
+ agentfort scan --repo . --format md --output report.md
67
+
68
+ # Only show high and above
69
+ agentfort scan --repo . --min-severity high
70
+
71
+ # Disable CI exit code
72
+ agentfort scan --repo . --no-fail-on-critical
73
+
74
+ # Skip OSV live lookup (air-gapped / CI without outbound)
75
+ agentfort scan --repo . --offline
76
+
77
+ # Browse advisories
78
+ agentfort advisories list
79
+ agentfort advisories list --severity critical
80
+ agentfort advisories show AGSA-001
81
+ ```
82
+
83
+ ## Live CVE lookup (OSV.dev)
84
+
85
+ Every scan queries [OSV.dev](https://osv.dev) in parallel for known CVEs against every package detected in the repo. No database to update — findings reflect OSV's current state on each run.
86
+
87
+ - Results are capped at 5 CVEs per package (highest severity first) to avoid noise from very old pinned versions
88
+ - Uses GHSA severity labels (`database_specific.severity`) for accurate critical/high/medium/low mapping
89
+ - Falls back silently if the network is unreachable — use `--offline` to skip the lookup entirely
90
+
91
+ ```bash
92
+ # Scan with live CVEs (default)
93
+ agentfort scan --repo .
94
+
95
+ # Air-gapped / no outbound network
96
+ agentfort scan --repo . --offline
97
+ ```
98
+
99
+ ## Advisory database
100
+
101
+ 14 static advisories covering structural/behavioral risks from the [OWASP Agentic Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/). Package CVEs are handled live by OSV.dev (see above).
102
+
103
+ | ID | Severity | Risk |
104
+ |---|---|---|
105
+ | AGSA-001 | Critical | LangChain ShellTool unrestricted shell execution |
106
+ | AGSA-002 | Critical | MCP server exposes shell execution tool |
107
+ | AGSA-003 | Critical | `eval()`/`exec()` in agent tool handler |
108
+ | AGSA-005 | Critical | AutoGen/CrewAI code execution without confirmation |
109
+ | AGSA-004 | High | Hardcoded API key or secret in MCP config |
110
+ | AGSA-006 | High | MCP filesystem server with overly broad path (`/`, `~`) |
111
+ | AGSA-007 | High | `subprocess` with `shell=True` or `os.system()` |
112
+ | AGSA-008 | High | Agent tool writes to arbitrary file paths |
113
+ | AGSA-010 | High | Prompt injection via unvalidated tool output |
114
+ | AGSA-013 | High | OpenAI Assistants `file_search`/`code_interpreter` without scope restriction |
115
+ | AGSA-009 | Medium | MCP server loaded via unverified `npx`/`uvx` package |
116
+ | AGSA-012 | Medium | Secrets exposed via `os.environ` in tool scope |
117
+ | AGSA-014 | Medium | Non-PyPI/non-npm dependency as framework component |
118
+ | AGSA-015 | Medium | System prompt in user-accessible config location |
119
+
120
+ ## Risk score
121
+
122
+ `0–100`. Each finding adds: critical=40, high=15, medium=5, low=1. Capped at 100.
123
+
124
+ ## Output formats
125
+
126
+ **Terminal** (default) — Rich panels with color-coded severity table and detail panels for critical/high findings.
127
+
128
+ **JSON** — Machine-readable. Progress messages go to stderr so stdout is clean for piping:
129
+ ```bash
130
+ agentfort scan --repo . --format json 2>/dev/null | jq '.findings[] | select(.severity=="critical")'
131
+ ```
132
+
133
+ **Markdown** — Full report with summary table and per-finding sections, suitable for GitHub issues or PR comments.
134
+
135
+ ## Project structure
136
+
137
+ ```
138
+ agentsentry/
139
+ ├── agentsentry/
140
+ │ ├── cli.py # Click CLI entry point
141
+ │ ├── models.py # Finding, ScanResult dataclasses
142
+ │ ├── db/
143
+ │ │ ├── advisory.py # Advisory loader and index
144
+ │ │ └── data/ # AGSA-001.yaml … AGSA-015.yaml
145
+ │ ├── scanner/
146
+ │ │ ├── frameworks.py # requirements.txt / pyproject.toml / package.json
147
+ │ │ ├── mcp.py # MCP config file scanner
148
+ │ │ ├── osv.py # Live CVE lookup via OSV.dev API
149
+ │ │ ├── patterns.py # Python source pattern scanner
150
+ │ │ └── secrets.py # Hardcoded credential scanner
151
+ │ └── report/
152
+ │ └── formatter.py # Terminal, Markdown, JSON renderers
153
+ └── pyproject.toml
154
+ ```
@@ -0,0 +1,125 @@
1
+ # AgentFort
2
+
3
+ Static security scanner for AI agent codebases. Analyzes repositories and MCP config files against a CVE-style advisory database — no live agent interaction required.
4
+
5
+ ## What it does
6
+
7
+ - Scans Python repos for dangerous patterns: `eval()`, `exec()`, `shell=True`, hardcoded API keys
8
+ - Parses MCP config files (`claude_desktop_config.json`, `.mcp.json`) for shell execution tools, overly broad filesystem access, and unverified `npx`/`uvx` packages
9
+ - Detects agent framework imports (LangChain, CrewAI, AutoGen, OpenAI, Anthropic, etc.) and cross-references against known vulnerabilities
10
+ - **Queries OSV.dev live** for real CVEs against every detected package — findings stay current without any database updates
11
+ - Produces risk scores, terminal reports, Markdown, and JSON output
12
+ - Exits with code 1 on critical findings — CI pipeline friendly
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ # From repo root (inside a virtualenv)
18
+ pip install agentfort
19
+
20
+ # Or dev install from repo
21
+ pip install -e agentsentry/
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ # Scan a repo
28
+ agentfort scan --repo /path/to/your/agent-project
29
+
30
+ # Scan just an MCP config file
31
+ agentfort scan --mcp-config ~/.config/claude/claude_desktop_config.json
32
+
33
+ # JSON output (clean stdout, progress on stderr)
34
+ agentfort scan --repo . --format json
35
+
36
+ # Markdown report to file
37
+ agentfort scan --repo . --format md --output report.md
38
+
39
+ # Only show high and above
40
+ agentfort scan --repo . --min-severity high
41
+
42
+ # Disable CI exit code
43
+ agentfort scan --repo . --no-fail-on-critical
44
+
45
+ # Skip OSV live lookup (air-gapped / CI without outbound)
46
+ agentfort scan --repo . --offline
47
+
48
+ # Browse advisories
49
+ agentfort advisories list
50
+ agentfort advisories list --severity critical
51
+ agentfort advisories show AGSA-001
52
+ ```
53
+
54
+ ## Live CVE lookup (OSV.dev)
55
+
56
+ Every scan queries [OSV.dev](https://osv.dev) in parallel for known CVEs against every package detected in the repo. No database to update — findings reflect OSV's current state on each run.
57
+
58
+ - Results are capped at 5 CVEs per package (highest severity first) to avoid noise from very old pinned versions
59
+ - Uses GHSA severity labels (`database_specific.severity`) for accurate critical/high/medium/low mapping
60
+ - Falls back silently if the network is unreachable — use `--offline` to skip the lookup entirely
61
+
62
+ ```bash
63
+ # Scan with live CVEs (default)
64
+ agentfort scan --repo .
65
+
66
+ # Air-gapped / no outbound network
67
+ agentfort scan --repo . --offline
68
+ ```
69
+
70
+ ## Advisory database
71
+
72
+ 14 static advisories covering structural/behavioral risks from the [OWASP Agentic Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/). Package CVEs are handled live by OSV.dev (see above).
73
+
74
+ | ID | Severity | Risk |
75
+ |---|---|---|
76
+ | AGSA-001 | Critical | LangChain ShellTool unrestricted shell execution |
77
+ | AGSA-002 | Critical | MCP server exposes shell execution tool |
78
+ | AGSA-003 | Critical | `eval()`/`exec()` in agent tool handler |
79
+ | AGSA-005 | Critical | AutoGen/CrewAI code execution without confirmation |
80
+ | AGSA-004 | High | Hardcoded API key or secret in MCP config |
81
+ | AGSA-006 | High | MCP filesystem server with overly broad path (`/`, `~`) |
82
+ | AGSA-007 | High | `subprocess` with `shell=True` or `os.system()` |
83
+ | AGSA-008 | High | Agent tool writes to arbitrary file paths |
84
+ | AGSA-010 | High | Prompt injection via unvalidated tool output |
85
+ | AGSA-013 | High | OpenAI Assistants `file_search`/`code_interpreter` without scope restriction |
86
+ | AGSA-009 | Medium | MCP server loaded via unverified `npx`/`uvx` package |
87
+ | AGSA-012 | Medium | Secrets exposed via `os.environ` in tool scope |
88
+ | AGSA-014 | Medium | Non-PyPI/non-npm dependency as framework component |
89
+ | AGSA-015 | Medium | System prompt in user-accessible config location |
90
+
91
+ ## Risk score
92
+
93
+ `0–100`. Each finding adds: critical=40, high=15, medium=5, low=1. Capped at 100.
94
+
95
+ ## Output formats
96
+
97
+ **Terminal** (default) — Rich panels with color-coded severity table and detail panels for critical/high findings.
98
+
99
+ **JSON** — Machine-readable. Progress messages go to stderr so stdout is clean for piping:
100
+ ```bash
101
+ agentfort scan --repo . --format json 2>/dev/null | jq '.findings[] | select(.severity=="critical")'
102
+ ```
103
+
104
+ **Markdown** — Full report with summary table and per-finding sections, suitable for GitHub issues or PR comments.
105
+
106
+ ## Project structure
107
+
108
+ ```
109
+ agentsentry/
110
+ ├── agentsentry/
111
+ │ ├── cli.py # Click CLI entry point
112
+ │ ├── models.py # Finding, ScanResult dataclasses
113
+ │ ├── db/
114
+ │ │ ├── advisory.py # Advisory loader and index
115
+ │ │ └── data/ # AGSA-001.yaml … AGSA-015.yaml
116
+ │ ├── scanner/
117
+ │ │ ├── frameworks.py # requirements.txt / pyproject.toml / package.json
118
+ │ │ ├── mcp.py # MCP config file scanner
119
+ │ │ ├── osv.py # Live CVE lookup via OSV.dev API
120
+ │ │ ├── patterns.py # Python source pattern scanner
121
+ │ │ └── secrets.py # Hardcoded credential scanner
122
+ │ └── report/
123
+ │ └── formatter.py # Terminal, Markdown, JSON renderers
124
+ └── pyproject.toml
125
+ ```
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentfort
3
+ Version: 0.1.1
4
+ Summary: CVE-style advisory database and static scanner for AI agent security risks
5
+ Author-email: NeuronKnight <dev@neuronknight.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/NeuronKnight/agentfort
8
+ Project-URL: Source, https://github.com/NeuronKnight/agentfort
9
+ Project-URL: Issues, https://github.com/NeuronKnight/agentfort/issues
10
+ Keywords: security,ai,agents,mcp,llm,scanner,langchain,crewai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: click>=8.0
24
+ Requires-Dist: rich>=13.0
25
+ Requires-Dist: pyyaml>=6.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # AgentFort
31
+
32
+ Static security scanner for AI agent codebases. Analyzes repositories and MCP config files against a CVE-style advisory database — no live agent interaction required.
33
+
34
+ ## What it does
35
+
36
+ - Scans Python repos for dangerous patterns: `eval()`, `exec()`, `shell=True`, hardcoded API keys
37
+ - Parses MCP config files (`claude_desktop_config.json`, `.mcp.json`) for shell execution tools, overly broad filesystem access, and unverified `npx`/`uvx` packages
38
+ - Detects agent framework imports (LangChain, CrewAI, AutoGen, OpenAI, Anthropic, etc.) and cross-references against known vulnerabilities
39
+ - **Queries OSV.dev live** for real CVEs against every detected package — findings stay current without any database updates
40
+ - Produces risk scores, terminal reports, Markdown, and JSON output
41
+ - Exits with code 1 on critical findings — CI pipeline friendly
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ # From repo root (inside a virtualenv)
47
+ pip install agentfort
48
+
49
+ # Or dev install from repo
50
+ pip install -e agentsentry/
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ```bash
56
+ # Scan a repo
57
+ agentfort scan --repo /path/to/your/agent-project
58
+
59
+ # Scan just an MCP config file
60
+ agentfort scan --mcp-config ~/.config/claude/claude_desktop_config.json
61
+
62
+ # JSON output (clean stdout, progress on stderr)
63
+ agentfort scan --repo . --format json
64
+
65
+ # Markdown report to file
66
+ agentfort scan --repo . --format md --output report.md
67
+
68
+ # Only show high and above
69
+ agentfort scan --repo . --min-severity high
70
+
71
+ # Disable CI exit code
72
+ agentfort scan --repo . --no-fail-on-critical
73
+
74
+ # Skip OSV live lookup (air-gapped / CI without outbound)
75
+ agentfort scan --repo . --offline
76
+
77
+ # Browse advisories
78
+ agentfort advisories list
79
+ agentfort advisories list --severity critical
80
+ agentfort advisories show AGSA-001
81
+ ```
82
+
83
+ ## Live CVE lookup (OSV.dev)
84
+
85
+ Every scan queries [OSV.dev](https://osv.dev) in parallel for known CVEs against every package detected in the repo. No database to update — findings reflect OSV's current state on each run.
86
+
87
+ - Results are capped at 5 CVEs per package (highest severity first) to avoid noise from very old pinned versions
88
+ - Uses GHSA severity labels (`database_specific.severity`) for accurate critical/high/medium/low mapping
89
+ - Falls back silently if the network is unreachable — use `--offline` to skip the lookup entirely
90
+
91
+ ```bash
92
+ # Scan with live CVEs (default)
93
+ agentfort scan --repo .
94
+
95
+ # Air-gapped / no outbound network
96
+ agentfort scan --repo . --offline
97
+ ```
98
+
99
+ ## Advisory database
100
+
101
+ 14 static advisories covering structural/behavioral risks from the [OWASP Agentic Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/). Package CVEs are handled live by OSV.dev (see above).
102
+
103
+ | ID | Severity | Risk |
104
+ |---|---|---|
105
+ | AGSA-001 | Critical | LangChain ShellTool unrestricted shell execution |
106
+ | AGSA-002 | Critical | MCP server exposes shell execution tool |
107
+ | AGSA-003 | Critical | `eval()`/`exec()` in agent tool handler |
108
+ | AGSA-005 | Critical | AutoGen/CrewAI code execution without confirmation |
109
+ | AGSA-004 | High | Hardcoded API key or secret in MCP config |
110
+ | AGSA-006 | High | MCP filesystem server with overly broad path (`/`, `~`) |
111
+ | AGSA-007 | High | `subprocess` with `shell=True` or `os.system()` |
112
+ | AGSA-008 | High | Agent tool writes to arbitrary file paths |
113
+ | AGSA-010 | High | Prompt injection via unvalidated tool output |
114
+ | AGSA-013 | High | OpenAI Assistants `file_search`/`code_interpreter` without scope restriction |
115
+ | AGSA-009 | Medium | MCP server loaded via unverified `npx`/`uvx` package |
116
+ | AGSA-012 | Medium | Secrets exposed via `os.environ` in tool scope |
117
+ | AGSA-014 | Medium | Non-PyPI/non-npm dependency as framework component |
118
+ | AGSA-015 | Medium | System prompt in user-accessible config location |
119
+
120
+ ## Risk score
121
+
122
+ `0–100`. Each finding adds: critical=40, high=15, medium=5, low=1. Capped at 100.
123
+
124
+ ## Output formats
125
+
126
+ **Terminal** (default) — Rich panels with color-coded severity table and detail panels for critical/high findings.
127
+
128
+ **JSON** — Machine-readable. Progress messages go to stderr so stdout is clean for piping:
129
+ ```bash
130
+ agentfort scan --repo . --format json 2>/dev/null | jq '.findings[] | select(.severity=="critical")'
131
+ ```
132
+
133
+ **Markdown** — Full report with summary table and per-finding sections, suitable for GitHub issues or PR comments.
134
+
135
+ ## Project structure
136
+
137
+ ```
138
+ agentsentry/
139
+ ├── agentsentry/
140
+ │ ├── cli.py # Click CLI entry point
141
+ │ ├── models.py # Finding, ScanResult dataclasses
142
+ │ ├── db/
143
+ │ │ ├── advisory.py # Advisory loader and index
144
+ │ │ └── data/ # AGSA-001.yaml … AGSA-015.yaml
145
+ │ ├── scanner/
146
+ │ │ ├── frameworks.py # requirements.txt / pyproject.toml / package.json
147
+ │ │ ├── mcp.py # MCP config file scanner
148
+ │ │ ├── osv.py # Live CVE lookup via OSV.dev API
149
+ │ │ ├── patterns.py # Python source pattern scanner
150
+ │ │ └── secrets.py # Hardcoded credential scanner
151
+ │ └── report/
152
+ │ └── formatter.py # Terminal, Markdown, JSON renderers
153
+ └── pyproject.toml
154
+ ```
@@ -0,0 +1,37 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ agentfort.egg-info/PKG-INFO
5
+ agentfort.egg-info/SOURCES.txt
6
+ agentfort.egg-info/dependency_links.txt
7
+ agentfort.egg-info/entry_points.txt
8
+ agentfort.egg-info/requires.txt
9
+ agentfort.egg-info/top_level.txt
10
+ agentsentry/__init__.py
11
+ agentsentry/cli.py
12
+ agentsentry/models.py
13
+ agentsentry/db/__init__.py
14
+ agentsentry/db/advisory.py
15
+ agentsentry/db/data/AGSA-001.yaml
16
+ agentsentry/db/data/AGSA-002.yaml
17
+ agentsentry/db/data/AGSA-003.yaml
18
+ agentsentry/db/data/AGSA-004.yaml
19
+ agentsentry/db/data/AGSA-005.yaml
20
+ agentsentry/db/data/AGSA-006.yaml
21
+ agentsentry/db/data/AGSA-007.yaml
22
+ agentsentry/db/data/AGSA-008.yaml
23
+ agentsentry/db/data/AGSA-009.yaml
24
+ agentsentry/db/data/AGSA-010.yaml
25
+ agentsentry/db/data/AGSA-012.yaml
26
+ agentsentry/db/data/AGSA-013.yaml
27
+ agentsentry/db/data/AGSA-014.yaml
28
+ agentsentry/db/data/AGSA-015.yaml
29
+ agentsentry/report/__init__.py
30
+ agentsentry/report/formatter.py
31
+ agentsentry/scanner/__init__.py
32
+ agentsentry/scanner/frameworks.py
33
+ agentsentry/scanner/mcp.py
34
+ agentsentry/scanner/osv.py
35
+ agentsentry/scanner/patterns.py
36
+ agentsentry/scanner/secrets.py
37
+ tests/test_scanners.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ agentfort = agentsentry.cli:cli
@@ -0,0 +1,6 @@
1
+ click>=8.0
2
+ rich>=13.0
3
+ pyyaml>=6.0
4
+
5
+ [dev]
6
+ pytest>=8.0
@@ -0,0 +1 @@
1
+ agentsentry
File without changes
@@ -0,0 +1,173 @@
1
+ import sys
2
+ import time
3
+ from pathlib import Path
4
+
5
+ import click
6
+ from rich.console import Console
7
+
8
+ from agentsentry.models import ScanResult, SEVERITY_ORDER
9
+ from agentsentry.db.advisory import load_advisories
10
+ from agentsentry.scanner.frameworks import scan_frameworks, detect_packages
11
+ from agentsentry.scanner.mcp import scan_mcp
12
+ from agentsentry.scanner.osv import scan_osv
13
+ from agentsentry.scanner.patterns import scan_patterns
14
+ from agentsentry.scanner.secrets import scan_secrets
15
+ from agentsentry.report.formatter import render_terminal, render_markdown, render_json
16
+
17
+ console = Console()
18
+ err_console = Console(stderr=True)
19
+
20
+
21
+ @click.group()
22
+ @click.version_option("0.1.1", prog_name="agentfort")
23
+ def cli():
24
+ """AgentFort — static scanner for AI agent security risks."""
25
+ pass
26
+
27
+
28
+ @cli.command()
29
+ @click.option("--repo", type=click.Path(exists=True, file_okay=False, path_type=Path),
30
+ default=None, help="Path to the repository to scan.")
31
+ @click.option("--mcp-config", type=click.Path(exists=True, dir_okay=False, path_type=Path),
32
+ default=None, help="Path to a specific MCP config file to scan.")
33
+ @click.option("--format", "fmt", type=click.Choice(["terminal", "md", "json"]), default="terminal",
34
+ show_default=True, help="Output format.")
35
+ @click.option("--output", "-o", type=click.Path(path_type=Path), default=None,
36
+ help="Write report to a file instead of stdout.")
37
+ @click.option("--min-severity", type=click.Choice(SEVERITY_ORDER), default="low",
38
+ show_default=True, help="Only show findings at or above this severity.")
39
+ @click.option("--fail-on-critical/--no-fail-on-critical", default=True, show_default=True,
40
+ help="Exit with code 1 if any critical findings exist.")
41
+ @click.option("--offline/--no-offline", default=False, show_default=True,
42
+ help="Skip OSV.dev live CVE lookup (use for air-gapped or CI environments).")
43
+ def scan(repo, mcp_config, fmt, output, min_severity, fail_on_critical, offline):
44
+ """Scan a repository or MCP config file for AI agent security risks."""
45
+
46
+ if not repo and not mcp_config:
47
+ # Default to current directory
48
+ repo = Path(".")
49
+
50
+ start = time.monotonic()
51
+ advisories = load_advisories()
52
+ findings = []
53
+
54
+ if repo:
55
+ err_console.print(f"[dim]Scanning repository: {repo.resolve()}[/dim]")
56
+ findings.extend(scan_frameworks(repo, advisories))
57
+ findings.extend(scan_mcp(repo_path=repo))
58
+ findings.extend(scan_patterns(repo, advisories))
59
+ findings.extend(scan_secrets(repo))
60
+ if not offline:
61
+ err_console.print("[dim]Querying OSV.dev for live CVEs...[/dim]")
62
+ packages = detect_packages(repo)
63
+ findings.extend(scan_osv(packages))
64
+
65
+ if mcp_config:
66
+ err_console.print(f"[dim]Scanning MCP config: {mcp_config.resolve()}[/dim]")
67
+ findings.extend(scan_mcp(config_path=mcp_config))
68
+
69
+ elapsed = time.monotonic() - start
70
+ result = ScanResult(
71
+ findings=findings,
72
+ scanned_path=repo or mcp_config,
73
+ scan_duration_seconds=elapsed,
74
+ )
75
+
76
+ if min_severity != "low":
77
+ result = result.filter_min_severity(min_severity)
78
+
79
+ if fmt == "terminal":
80
+ if output:
81
+ # Write terminal-stripped output to file
82
+ from rich.console import Console as RichConsole
83
+ file_console = RichConsole(file=open(output, "w"), highlight=False)
84
+ render_terminal(result)
85
+ else:
86
+ render_terminal(result)
87
+ report_str = None
88
+ elif fmt == "md":
89
+ report_str = render_markdown(result)
90
+ else:
91
+ report_str = render_json(result)
92
+
93
+ if report_str is not None:
94
+ if output:
95
+ output.write_text(report_str)
96
+ console.print(f"[green]Report written to {output}[/green]")
97
+ else:
98
+ click.echo(report_str)
99
+
100
+ if fail_on_critical and any(f.severity == "critical" for f in result.findings):
101
+ sys.exit(1)
102
+
103
+
104
+ @cli.group()
105
+ def advisories():
106
+ """Manage and browse the advisory database."""
107
+ pass
108
+
109
+
110
+ @advisories.command("list")
111
+ @click.option("--severity", type=click.Choice(SEVERITY_ORDER + ["all"]), default="all",
112
+ help="Filter by severity.")
113
+ def advisories_list(severity):
114
+ """List all advisories in the database."""
115
+ from rich.table import Table
116
+ from rich import box
117
+
118
+ adv_list = load_advisories()
119
+ if severity != "all":
120
+ adv_list = [a for a in adv_list if a.severity == severity]
121
+
122
+ table = Table(box=box.ROUNDED, expand=True)
123
+ table.add_column("ID", style="bold cyan", width=12)
124
+ table.add_column("Severity", width=10)
125
+ table.add_column("Frameworks", width=20)
126
+ table.add_column("Title")
127
+
128
+ from agentsentry.report.formatter import SEVERITY_COLORS, SEVERITY_EMOJI
129
+ from rich.text import Text
130
+
131
+ for adv in sorted(adv_list, key=lambda a: (SEVERITY_ORDER.index(a.severity), a.id)):
132
+ sev_text = Text(
133
+ f"{SEVERITY_EMOJI.get(adv.severity, '')} {adv.severity.upper()}",
134
+ style=SEVERITY_COLORS.get(adv.severity, "white"),
135
+ )
136
+ frameworks = ", ".join(adv.frameworks[:3]) + ("..." if len(adv.frameworks) > 3 else "")
137
+ table.add_row(adv.id, sev_text, frameworks, adv.title)
138
+
139
+ console.print(table)
140
+ console.print(f"\n[dim]{len(adv_list)} advisories[/dim]")
141
+
142
+
143
+ @advisories.command("show")
144
+ @click.argument("advisory_id")
145
+ def advisories_show(advisory_id):
146
+ """Show full detail for an advisory by ID."""
147
+ from rich.panel import Panel
148
+ from rich.markdown import Markdown
149
+
150
+ adv_list = load_advisories()
151
+ adv = next((a for a in adv_list if a.id.upper() == advisory_id.upper()), None)
152
+ if not adv:
153
+ console.print(f"[red]Advisory {advisory_id} not found.[/red]")
154
+ sys.exit(1)
155
+
156
+ from agentsentry.report.formatter import SEVERITY_COLORS, SEVERITY_EMOJI
157
+ color = SEVERITY_COLORS.get(adv.severity, "white")
158
+
159
+ content = (
160
+ f"**Severity:** {adv.severity.upper()}\n"
161
+ f"**Frameworks:** {', '.join(adv.frameworks)}\n"
162
+ f"**Attack Types:** {', '.join(adv.attack_types)}\n\n"
163
+ f"**Description:**\n{adv.description}\n\n"
164
+ f"**Mitigation:**\n{adv.mitigation}\n\n"
165
+ f"**References:**\n" + "\n".join(f"- {r}" for r in adv.references)
166
+ )
167
+
168
+ console.print(Panel(
169
+ Markdown(content),
170
+ title=f"[{color}]{SEVERITY_EMOJI.get(adv.severity, '')} {adv.id}: {adv.title}[/{color}]",
171
+ border_style=color.replace("bold ", ""),
172
+ padding=(1, 2),
173
+ ))