cobaltosec-corvus 0.7.0__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 (62) hide show
  1. cobaltosec_corvus-0.7.0/PKG-INFO +339 -0
  2. cobaltosec_corvus-0.7.0/README.md +314 -0
  3. cobaltosec_corvus-0.7.0/cobaltosec_corvus.egg-info/PKG-INFO +339 -0
  4. cobaltosec_corvus-0.7.0/cobaltosec_corvus.egg-info/SOURCES.txt +60 -0
  5. cobaltosec_corvus-0.7.0/cobaltosec_corvus.egg-info/dependency_links.txt +1 -0
  6. cobaltosec_corvus-0.7.0/cobaltosec_corvus.egg-info/entry_points.txt +2 -0
  7. cobaltosec_corvus-0.7.0/cobaltosec_corvus.egg-info/requires.txt +12 -0
  8. cobaltosec_corvus-0.7.0/cobaltosec_corvus.egg-info/top_level.txt +2 -0
  9. cobaltosec_corvus-0.7.0/corvus/__init__.py +3 -0
  10. cobaltosec_corvus-0.7.0/corvus/batch.py +161 -0
  11. cobaltosec_corvus-0.7.0/corvus/cli.py +399 -0
  12. cobaltosec_corvus-0.7.0/corvus/config.py +40 -0
  13. cobaltosec_corvus-0.7.0/corvus/core/__init__.py +0 -0
  14. cobaltosec_corvus-0.7.0/corvus/core/models.py +97 -0
  15. cobaltosec_corvus-0.7.0/corvus/core/session.py +41 -0
  16. cobaltosec_corvus-0.7.0/corvus/discovery/__init__.py +0 -0
  17. cobaltosec_corvus-0.7.0/corvus/discovery/enumerator.py +84 -0
  18. cobaltosec_corvus-0.7.0/corvus/modules/__init__.py +0 -0
  19. cobaltosec_corvus-0.7.0/corvus/modules/base.py +23 -0
  20. cobaltosec_corvus-0.7.0/corvus/modules/dynamic/__init__.py +0 -0
  21. cobaltosec_corvus-0.7.0/corvus/modules/dynamic/info_disclosure.py +139 -0
  22. cobaltosec_corvus-0.7.0/corvus/modules/dynamic/param_injection.py +199 -0
  23. cobaltosec_corvus-0.7.0/corvus/modules/dynamic/response_flood.py +117 -0
  24. cobaltosec_corvus-0.7.0/corvus/modules/dynamic/rug_pull.py +128 -0
  25. cobaltosec_corvus-0.7.0/corvus/modules/dynamic/schema_bypass.py +103 -0
  26. cobaltosec_corvus-0.7.0/corvus/modules/static/__init__.py +0 -0
  27. cobaltosec_corvus-0.7.0/corvus/modules/static/auth_audit.py +148 -0
  28. cobaltosec_corvus-0.7.0/corvus/modules/static/log_audit.py +165 -0
  29. cobaltosec_corvus-0.7.0/corvus/modules/static/schema_audit.py +77 -0
  30. cobaltosec_corvus-0.7.0/corvus/modules/static/shadow_tool.py +116 -0
  31. cobaltosec_corvus-0.7.0/corvus/modules/static/tool_poisoning.py +110 -0
  32. cobaltosec_corvus-0.7.0/corvus/payloads/__init__.py +0 -0
  33. cobaltosec_corvus-0.7.0/corvus/payloads/data/injection.yaml +59 -0
  34. cobaltosec_corvus-0.7.0/corvus/payloads/data/poisoning_patterns.yaml +37 -0
  35. cobaltosec_corvus-0.7.0/corvus/payloads/data/schema_bypass.yaml +36 -0
  36. cobaltosec_corvus-0.7.0/corvus/payloads/data/traversal.yaml +26 -0
  37. cobaltosec_corvus-0.7.0/corvus/payloads/engine.py +85 -0
  38. cobaltosec_corvus-0.7.0/corvus/plugins.py +112 -0
  39. cobaltosec_corvus-0.7.0/corvus/reporting/__init__.py +0 -0
  40. cobaltosec_corvus-0.7.0/corvus/reporting/report.py +111 -0
  41. cobaltosec_corvus-0.7.0/corvus/reporting/templates/report.md.j2 +76 -0
  42. cobaltosec_corvus-0.7.0/corvus/transport/__init__.py +0 -0
  43. cobaltosec_corvus-0.7.0/corvus/transport/base.py +53 -0
  44. cobaltosec_corvus-0.7.0/corvus/transport/http.py +118 -0
  45. cobaltosec_corvus-0.7.0/corvus/transport/sse.py +3 -0
  46. cobaltosec_corvus-0.7.0/corvus/transport/stdio.py +145 -0
  47. cobaltosec_corvus-0.7.0/pyproject.toml +54 -0
  48. cobaltosec_corvus-0.7.0/setup.cfg +4 -0
  49. cobaltosec_corvus-0.7.0/tests/test_batch.py +86 -0
  50. cobaltosec_corvus-0.7.0/tests/test_config.py +81 -0
  51. cobaltosec_corvus-0.7.0/tests/test_discovery.py +26 -0
  52. cobaltosec_corvus-0.7.0/tests/test_enumerator_listchanged.py +40 -0
  53. cobaltosec_corvus-0.7.0/tests/test_modules.py +176 -0
  54. cobaltosec_corvus-0.7.0/tests/test_modules_v2.py +112 -0
  55. cobaltosec_corvus-0.7.0/tests/test_modules_v3.py +105 -0
  56. cobaltosec_corvus-0.7.0/tests/test_modules_v4.py +58 -0
  57. cobaltosec_corvus-0.7.0/tests/test_modules_v5.py +275 -0
  58. cobaltosec_corvus-0.7.0/tests/test_plugins.py +137 -0
  59. cobaltosec_corvus-0.7.0/tests/test_request_logging.py +65 -0
  60. cobaltosec_corvus-0.7.0/tests/test_sarif.py +120 -0
  61. cobaltosec_corvus-0.7.0/tests/test_transport.py +64 -0
  62. cobaltosec_corvus-0.7.0/tests/test_transport_http.py +87 -0
@@ -0,0 +1,339 @@
1
+ Metadata-Version: 2.4
2
+ Name: cobaltosec-corvus
3
+ Version: 0.7.0
4
+ Summary: MCP server security testing framework
5
+ License: MIT
6
+ Keywords: mcp,security,testing,llm,ai
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Topic :: Security
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: typer>=0.12
15
+ Requires-Dist: httpx>=0.27
16
+ Requires-Dist: pydantic>=2.5
17
+ Requires-Dist: rich>=13
18
+ Requires-Dist: PyYAML>=6
19
+ Requires-Dist: jinja2>=3
20
+ Requires-Dist: anyio>=4
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8; extra == "dev"
23
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
24
+ Requires-Dist: ruff>=0.4; extra == "dev"
25
+
26
+ # Corvus
27
+
28
+ MCP server security testing framework. Tests MCP servers against the [OWASP MCP Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/) — both static analysis and live dynamic probing.
29
+
30
+ ```
31
+ Corvus v0.7.0 MCP Security Scanner
32
+ Target : python my_mcp_server.py
33
+ Transport : stdio
34
+ Modules : tool-poisoning, schema-audit, shadow-tool, auth-audit, log-audit,
35
+ param-injection, info-disclosure, schema-bypass, response-flood, rug-pull
36
+
37
+ Enumerating surface...
38
+ Tools : 12
39
+ Resources : 3
40
+ Prompts : 2
41
+ Server : my-server 1.0.0
42
+
43
+ [MCP01] Tool Poisoning (static)
44
+ [HIGH] Potential prompt injection in description of 'execute_code'
45
+
46
+ [MCP02] Parameter Injection (dynamic)
47
+ [HIGH] Command injection confirmed in tool 'run_shell', param 'command'
48
+ [MEDIUM] Path traversal accepted in tool 'read_file', param 'path'
49
+
50
+ ...
51
+
52
+ ─── Summary ──────────────────────────────────────────────────────────────────
53
+ CRITICAL 0 HIGH 2 MEDIUM 1 LOW 3 INFO 4
54
+ Session : corvus-sessions/20260608-143022/
55
+ ```
56
+
57
+ ## Install
58
+
59
+ ```bash
60
+ pip install cobaltosec-corvus
61
+ ```
62
+
63
+ Or from source:
64
+
65
+ ```bash
66
+ git clone https://github.com/CobaltoSec/corvus
67
+ cd corvus
68
+ pip install -e ".[dev]"
69
+ ```
70
+
71
+ ## Quick Start
72
+
73
+ ```bash
74
+ # Scan a stdio MCP server
75
+ corvus scan --transport stdio --cmd "python my_server.py"
76
+
77
+ # Scan an HTTP MCP server
78
+ corvus scan --transport http --url http://localhost:8080
79
+
80
+ # With authentication header
81
+ corvus scan --transport http --url http://localhost:8080 --header "Authorization: Bearer token"
82
+
83
+ # Static analysis only (no live tool calls)
84
+ corvus scan --transport stdio --cmd "python my_server.py" --module static
85
+
86
+ # Specific module
87
+ corvus scan --transport stdio --cmd "python my_server.py" --module param-injection
88
+
89
+ # SARIF output (for CI/CD integration)
90
+ corvus scan --transport stdio --cmd "python my_server.py" --sarif
91
+
92
+ # Fail CI on findings above threshold
93
+ corvus scan --transport stdio --cmd "python my_server.py" --fail-on high
94
+
95
+ # Load config from file
96
+ corvus scan --config corvus.toml
97
+
98
+ # Filter low-confidence findings (0-100)
99
+ corvus scan --transport stdio --cmd "python my_server.py" --min-confidence 70
100
+
101
+ # Capture raw JSON-RPC exchanges
102
+ corvus scan --transport stdio --cmd "python my_server.py" --log-requests
103
+
104
+ # List available modules
105
+ corvus list-modules
106
+ ```
107
+
108
+ ## Batch Scan
109
+
110
+ Scan multiple MCP servers in one invocation:
111
+
112
+ ```yaml
113
+ # targets.yaml
114
+ targets:
115
+ - name: filesystem
116
+ transport: stdio
117
+ cmd: ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
118
+
119
+ - name: my-http-server
120
+ transport: http
121
+ url: http://localhost:8080
122
+ ```
123
+
124
+ ```bash
125
+ corvus batch targets.yaml --output-dir results/ --sarif --min-confidence 70
126
+ ```
127
+
128
+ Produces a per-target `report.json` and a top-level `summary.md` table.
129
+
130
+ ## Modules
131
+
132
+ Full coverage of OWASP MCP Top 10:
133
+
134
+ | Name | OWASP | Type | What it tests |
135
+ |------|-------|------|---------------|
136
+ | `tool-poisoning` | MCP01 | static | Hidden instructions, obfuscation, and prompt injection patterns in tool descriptions |
137
+ | `param-injection` | MCP02 | dynamic | Command, path, prompt, and SQL injection payloads per parameter — schema-aware |
138
+ | `shadow-tool` | MCP03 | static | Tool names that shadow built-ins or signal dangerous operations (namespace squatting, trust hijacking) |
139
+ | `info-disclosure` | MCP04 | dynamic | Credentials, filesystem paths, stack traces, and tokens leaked in tool responses |
140
+ | `schema-bypass` | MCP05 | dynamic | Whether tools properly reject inputs that violate their declared schema |
141
+ | `rug-pull` | MCP06 | dynamic | Re-enumerates the server after dynamic testing; diffs against initial snapshot to detect added, removed, or mutated tools |
142
+ | `response-flood` | MCP07 | dynamic | Excessively large or highly repetitive responses that could overflow an LLM context window or inject looping instructions |
143
+ | `auth-audit` | MCP08 | static | Tool names and descriptions suggesting missing, optional, or bypassable authentication |
144
+ | `schema-audit` | MCP09 | static | Weak schema definitions (missing required fields, unconstrained types) that expand the attack surface |
145
+ | `log-audit` | MCP10 | static | Tools that expose or tamper with audit logs — enables anti-forensic techniques or leaks operational data |
146
+
147
+ ### Module groups
148
+
149
+ ```bash
150
+ # All modules (default)
151
+ --module all
152
+
153
+ # Static only (no live calls to the server)
154
+ --module static
155
+
156
+ # Dynamic only
157
+ --module dynamic
158
+
159
+ # Individual module
160
+ --module param-injection
161
+ ```
162
+
163
+ ## Transports
164
+
165
+ ### stdio
166
+
167
+ Spawns the server process and communicates via stdin/stdout. Supports any command:
168
+
169
+ ```bash
170
+ corvus scan --transport stdio --cmd "python server.py"
171
+ corvus scan --transport stdio --cmd "npx @modelcontextprotocol/server-filesystem /tmp"
172
+ corvus scan --transport stdio --cmd "uvx my-mcp-server --arg value"
173
+ ```
174
+
175
+ ### HTTP
176
+
177
+ Connects to a running HTTP/SSE MCP server:
178
+
179
+ ```bash
180
+ corvus scan --transport http --url http://localhost:8080
181
+
182
+ # With auth
183
+ corvus scan --transport http --url http://localhost:8080 --header "Authorization: Bearer $TOKEN"
184
+ corvus scan --transport http --url http://localhost:8080 --header "X-API-Key: secret"
185
+ ```
186
+
187
+ ## Config File
188
+
189
+ Create `corvus.toml` to avoid repeating CLI flags:
190
+
191
+ ```toml
192
+ [scan]
193
+ transport = "stdio"
194
+ cmd = "python my_server.py"
195
+ modules = "all"
196
+ timeout = 30
197
+ sarif = false
198
+ fail_on = "high"
199
+
200
+ [scan.headers]
201
+ "Authorization" = "Bearer my-token"
202
+ ```
203
+
204
+ Then run:
205
+
206
+ ```bash
207
+ corvus scan --config corvus.toml
208
+ ```
209
+
210
+ CLI flags override config file values. The `--config` flag also accepts absolute paths.
211
+
212
+ ## CLI Reference
213
+
214
+ ```
215
+ Usage: corvus scan [OPTIONS]
216
+
217
+ Scan an MCP server for security vulnerabilities.
218
+
219
+ Options:
220
+ -t, --transport TEXT stdio | http (overrides config)
221
+ --cmd TEXT Command to launch MCP server (stdio)
222
+ --url TEXT URL of MCP server (http)
223
+ -m, --module TEXT all | static | dynamic | <module-name> (overrides config)
224
+ -o, --output-dir PATH
225
+ --fail-on TEXT Exit 1 if findings at this severity or above
226
+ (critical|high|medium|low)
227
+ --timeout INTEGER Request timeout in seconds (overrides config)
228
+ --sarif Also write SARIF 2.1.0 report
229
+ --header TEXT HTTP header "Key: Value" (repeatable, for http transport)
230
+ -c, --config PATH Path to corvus.toml config file
231
+ --plugin-dir TEXT Directory to load external modules from (repeatable)
232
+ --help Show this message and exit.
233
+ ```
234
+
235
+ Other commands:
236
+
237
+ ```bash
238
+ corvus list-modules # list available modules with OWASP ID and type
239
+ corvus list-modules --plugin-dir ./plugins/ # include external plugins
240
+ corvus version # print version
241
+ ```
242
+
243
+ ## Output
244
+
245
+ Each scan creates a session directory under `corvus-sessions/<timestamp>/`:
246
+
247
+ ```
248
+ corvus-sessions/20260608-143022/
249
+ ├── report.json # full structured result
250
+ ├── report.md # human-readable with remediation guidance
251
+ └── report.sarif # SARIF 2.1.0 (only when --sarif is passed)
252
+ ```
253
+
254
+ ### SARIF integration
255
+
256
+ SARIF output is compatible with GitHub Advanced Security, VS Code SARIF Viewer, and any CI pipeline that consumes SARIF:
257
+
258
+ ```yaml
259
+ # GitHub Actions example
260
+ - name: Run Corvus
261
+ run: corvus scan --transport stdio --cmd "python server.py" --sarif --fail-on high
262
+
263
+ - name: Upload SARIF
264
+ uses: github/codeql-action/upload-sarif@v3
265
+ with:
266
+ sarif_file: corvus-sessions/
267
+ ```
268
+
269
+ ## CI Integration
270
+
271
+ ```bash
272
+ # Exit 1 if any CRITICAL findings
273
+ corvus scan --transport stdio --cmd "python server.py" --fail-on critical
274
+
275
+ # Exit 1 if any HIGH or above
276
+ corvus scan --transport stdio --cmd "python server.py" --fail-on high
277
+ ```
278
+
279
+ Severity levels (ascending): `info` → `low` → `medium` → `high` → `critical`
280
+
281
+ ## Plugin System
282
+
283
+ Add custom modules without modifying Corvus source.
284
+
285
+ ### Directory-based plugins
286
+
287
+ ```bash
288
+ corvus scan --transport stdio --cmd "python server.py" --plugin-dir ./my-modules/
289
+ ```
290
+
291
+ Each `.py` file in the directory is loaded as a module. The file must define a class that inherits from `BaseModule`:
292
+
293
+ ```python
294
+ from corvus.modules.base import BaseModule, Finding, Severity
295
+
296
+ class MyCustomModule(BaseModule):
297
+ name = "my-check"
298
+ owasp_id = "MCP-CUSTOM"
299
+ module_type = "static"
300
+ description = "Custom check for my organization"
301
+
302
+ async def run(self, surface, transport):
303
+ findings = []
304
+ for tool in surface.tools:
305
+ if "dangerous_pattern" in tool.description:
306
+ findings.append(Finding(
307
+ rule_id="MY001",
308
+ tool_name=tool.name,
309
+ severity=Severity.HIGH,
310
+ title="Dangerous pattern detected",
311
+ description=f"Tool '{tool.name}' contains a dangerous pattern.",
312
+ remediation="Remove or sanitize the pattern.",
313
+ ))
314
+ return findings
315
+ ```
316
+
317
+ ### Package-based plugins
318
+
319
+ Register via `pyproject.toml` entry points:
320
+
321
+ ```toml
322
+ [project.entry-points."corvus.modules"]
323
+ my-check = "my_package.modules.my_check:MyCustomModule"
324
+ ```
325
+
326
+ After `pip install my-package`, Corvus auto-discovers the module.
327
+
328
+ ## Development
329
+
330
+ ```bash
331
+ git clone https://github.com/CobaltoSec/corvus
332
+ cd corvus
333
+ pip install -e ".[dev]"
334
+ pytest
335
+ ```
336
+
337
+ ## License
338
+
339
+ MIT
@@ -0,0 +1,314 @@
1
+ # Corvus
2
+
3
+ MCP server security testing framework. Tests MCP servers against the [OWASP MCP Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/) — both static analysis and live dynamic probing.
4
+
5
+ ```
6
+ Corvus v0.7.0 MCP Security Scanner
7
+ Target : python my_mcp_server.py
8
+ Transport : stdio
9
+ Modules : tool-poisoning, schema-audit, shadow-tool, auth-audit, log-audit,
10
+ param-injection, info-disclosure, schema-bypass, response-flood, rug-pull
11
+
12
+ Enumerating surface...
13
+ Tools : 12
14
+ Resources : 3
15
+ Prompts : 2
16
+ Server : my-server 1.0.0
17
+
18
+ [MCP01] Tool Poisoning (static)
19
+ [HIGH] Potential prompt injection in description of 'execute_code'
20
+
21
+ [MCP02] Parameter Injection (dynamic)
22
+ [HIGH] Command injection confirmed in tool 'run_shell', param 'command'
23
+ [MEDIUM] Path traversal accepted in tool 'read_file', param 'path'
24
+
25
+ ...
26
+
27
+ ─── Summary ──────────────────────────────────────────────────────────────────
28
+ CRITICAL 0 HIGH 2 MEDIUM 1 LOW 3 INFO 4
29
+ Session : corvus-sessions/20260608-143022/
30
+ ```
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ pip install cobaltosec-corvus
36
+ ```
37
+
38
+ Or from source:
39
+
40
+ ```bash
41
+ git clone https://github.com/CobaltoSec/corvus
42
+ cd corvus
43
+ pip install -e ".[dev]"
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```bash
49
+ # Scan a stdio MCP server
50
+ corvus scan --transport stdio --cmd "python my_server.py"
51
+
52
+ # Scan an HTTP MCP server
53
+ corvus scan --transport http --url http://localhost:8080
54
+
55
+ # With authentication header
56
+ corvus scan --transport http --url http://localhost:8080 --header "Authorization: Bearer token"
57
+
58
+ # Static analysis only (no live tool calls)
59
+ corvus scan --transport stdio --cmd "python my_server.py" --module static
60
+
61
+ # Specific module
62
+ corvus scan --transport stdio --cmd "python my_server.py" --module param-injection
63
+
64
+ # SARIF output (for CI/CD integration)
65
+ corvus scan --transport stdio --cmd "python my_server.py" --sarif
66
+
67
+ # Fail CI on findings above threshold
68
+ corvus scan --transport stdio --cmd "python my_server.py" --fail-on high
69
+
70
+ # Load config from file
71
+ corvus scan --config corvus.toml
72
+
73
+ # Filter low-confidence findings (0-100)
74
+ corvus scan --transport stdio --cmd "python my_server.py" --min-confidence 70
75
+
76
+ # Capture raw JSON-RPC exchanges
77
+ corvus scan --transport stdio --cmd "python my_server.py" --log-requests
78
+
79
+ # List available modules
80
+ corvus list-modules
81
+ ```
82
+
83
+ ## Batch Scan
84
+
85
+ Scan multiple MCP servers in one invocation:
86
+
87
+ ```yaml
88
+ # targets.yaml
89
+ targets:
90
+ - name: filesystem
91
+ transport: stdio
92
+ cmd: ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
93
+
94
+ - name: my-http-server
95
+ transport: http
96
+ url: http://localhost:8080
97
+ ```
98
+
99
+ ```bash
100
+ corvus batch targets.yaml --output-dir results/ --sarif --min-confidence 70
101
+ ```
102
+
103
+ Produces a per-target `report.json` and a top-level `summary.md` table.
104
+
105
+ ## Modules
106
+
107
+ Full coverage of OWASP MCP Top 10:
108
+
109
+ | Name | OWASP | Type | What it tests |
110
+ |------|-------|------|---------------|
111
+ | `tool-poisoning` | MCP01 | static | Hidden instructions, obfuscation, and prompt injection patterns in tool descriptions |
112
+ | `param-injection` | MCP02 | dynamic | Command, path, prompt, and SQL injection payloads per parameter — schema-aware |
113
+ | `shadow-tool` | MCP03 | static | Tool names that shadow built-ins or signal dangerous operations (namespace squatting, trust hijacking) |
114
+ | `info-disclosure` | MCP04 | dynamic | Credentials, filesystem paths, stack traces, and tokens leaked in tool responses |
115
+ | `schema-bypass` | MCP05 | dynamic | Whether tools properly reject inputs that violate their declared schema |
116
+ | `rug-pull` | MCP06 | dynamic | Re-enumerates the server after dynamic testing; diffs against initial snapshot to detect added, removed, or mutated tools |
117
+ | `response-flood` | MCP07 | dynamic | Excessively large or highly repetitive responses that could overflow an LLM context window or inject looping instructions |
118
+ | `auth-audit` | MCP08 | static | Tool names and descriptions suggesting missing, optional, or bypassable authentication |
119
+ | `schema-audit` | MCP09 | static | Weak schema definitions (missing required fields, unconstrained types) that expand the attack surface |
120
+ | `log-audit` | MCP10 | static | Tools that expose or tamper with audit logs — enables anti-forensic techniques or leaks operational data |
121
+
122
+ ### Module groups
123
+
124
+ ```bash
125
+ # All modules (default)
126
+ --module all
127
+
128
+ # Static only (no live calls to the server)
129
+ --module static
130
+
131
+ # Dynamic only
132
+ --module dynamic
133
+
134
+ # Individual module
135
+ --module param-injection
136
+ ```
137
+
138
+ ## Transports
139
+
140
+ ### stdio
141
+
142
+ Spawns the server process and communicates via stdin/stdout. Supports any command:
143
+
144
+ ```bash
145
+ corvus scan --transport stdio --cmd "python server.py"
146
+ corvus scan --transport stdio --cmd "npx @modelcontextprotocol/server-filesystem /tmp"
147
+ corvus scan --transport stdio --cmd "uvx my-mcp-server --arg value"
148
+ ```
149
+
150
+ ### HTTP
151
+
152
+ Connects to a running HTTP/SSE MCP server:
153
+
154
+ ```bash
155
+ corvus scan --transport http --url http://localhost:8080
156
+
157
+ # With auth
158
+ corvus scan --transport http --url http://localhost:8080 --header "Authorization: Bearer $TOKEN"
159
+ corvus scan --transport http --url http://localhost:8080 --header "X-API-Key: secret"
160
+ ```
161
+
162
+ ## Config File
163
+
164
+ Create `corvus.toml` to avoid repeating CLI flags:
165
+
166
+ ```toml
167
+ [scan]
168
+ transport = "stdio"
169
+ cmd = "python my_server.py"
170
+ modules = "all"
171
+ timeout = 30
172
+ sarif = false
173
+ fail_on = "high"
174
+
175
+ [scan.headers]
176
+ "Authorization" = "Bearer my-token"
177
+ ```
178
+
179
+ Then run:
180
+
181
+ ```bash
182
+ corvus scan --config corvus.toml
183
+ ```
184
+
185
+ CLI flags override config file values. The `--config` flag also accepts absolute paths.
186
+
187
+ ## CLI Reference
188
+
189
+ ```
190
+ Usage: corvus scan [OPTIONS]
191
+
192
+ Scan an MCP server for security vulnerabilities.
193
+
194
+ Options:
195
+ -t, --transport TEXT stdio | http (overrides config)
196
+ --cmd TEXT Command to launch MCP server (stdio)
197
+ --url TEXT URL of MCP server (http)
198
+ -m, --module TEXT all | static | dynamic | <module-name> (overrides config)
199
+ -o, --output-dir PATH
200
+ --fail-on TEXT Exit 1 if findings at this severity or above
201
+ (critical|high|medium|low)
202
+ --timeout INTEGER Request timeout in seconds (overrides config)
203
+ --sarif Also write SARIF 2.1.0 report
204
+ --header TEXT HTTP header "Key: Value" (repeatable, for http transport)
205
+ -c, --config PATH Path to corvus.toml config file
206
+ --plugin-dir TEXT Directory to load external modules from (repeatable)
207
+ --help Show this message and exit.
208
+ ```
209
+
210
+ Other commands:
211
+
212
+ ```bash
213
+ corvus list-modules # list available modules with OWASP ID and type
214
+ corvus list-modules --plugin-dir ./plugins/ # include external plugins
215
+ corvus version # print version
216
+ ```
217
+
218
+ ## Output
219
+
220
+ Each scan creates a session directory under `corvus-sessions/<timestamp>/`:
221
+
222
+ ```
223
+ corvus-sessions/20260608-143022/
224
+ ├── report.json # full structured result
225
+ ├── report.md # human-readable with remediation guidance
226
+ └── report.sarif # SARIF 2.1.0 (only when --sarif is passed)
227
+ ```
228
+
229
+ ### SARIF integration
230
+
231
+ SARIF output is compatible with GitHub Advanced Security, VS Code SARIF Viewer, and any CI pipeline that consumes SARIF:
232
+
233
+ ```yaml
234
+ # GitHub Actions example
235
+ - name: Run Corvus
236
+ run: corvus scan --transport stdio --cmd "python server.py" --sarif --fail-on high
237
+
238
+ - name: Upload SARIF
239
+ uses: github/codeql-action/upload-sarif@v3
240
+ with:
241
+ sarif_file: corvus-sessions/
242
+ ```
243
+
244
+ ## CI Integration
245
+
246
+ ```bash
247
+ # Exit 1 if any CRITICAL findings
248
+ corvus scan --transport stdio --cmd "python server.py" --fail-on critical
249
+
250
+ # Exit 1 if any HIGH or above
251
+ corvus scan --transport stdio --cmd "python server.py" --fail-on high
252
+ ```
253
+
254
+ Severity levels (ascending): `info` → `low` → `medium` → `high` → `critical`
255
+
256
+ ## Plugin System
257
+
258
+ Add custom modules without modifying Corvus source.
259
+
260
+ ### Directory-based plugins
261
+
262
+ ```bash
263
+ corvus scan --transport stdio --cmd "python server.py" --plugin-dir ./my-modules/
264
+ ```
265
+
266
+ Each `.py` file in the directory is loaded as a module. The file must define a class that inherits from `BaseModule`:
267
+
268
+ ```python
269
+ from corvus.modules.base import BaseModule, Finding, Severity
270
+
271
+ class MyCustomModule(BaseModule):
272
+ name = "my-check"
273
+ owasp_id = "MCP-CUSTOM"
274
+ module_type = "static"
275
+ description = "Custom check for my organization"
276
+
277
+ async def run(self, surface, transport):
278
+ findings = []
279
+ for tool in surface.tools:
280
+ if "dangerous_pattern" in tool.description:
281
+ findings.append(Finding(
282
+ rule_id="MY001",
283
+ tool_name=tool.name,
284
+ severity=Severity.HIGH,
285
+ title="Dangerous pattern detected",
286
+ description=f"Tool '{tool.name}' contains a dangerous pattern.",
287
+ remediation="Remove or sanitize the pattern.",
288
+ ))
289
+ return findings
290
+ ```
291
+
292
+ ### Package-based plugins
293
+
294
+ Register via `pyproject.toml` entry points:
295
+
296
+ ```toml
297
+ [project.entry-points."corvus.modules"]
298
+ my-check = "my_package.modules.my_check:MyCustomModule"
299
+ ```
300
+
301
+ After `pip install my-package`, Corvus auto-discovers the module.
302
+
303
+ ## Development
304
+
305
+ ```bash
306
+ git clone https://github.com/CobaltoSec/corvus
307
+ cd corvus
308
+ pip install -e ".[dev]"
309
+ pytest
310
+ ```
311
+
312
+ ## License
313
+
314
+ MIT