Skip to main content

MCP server security testing framework

Project description

Corvus

MCP server security testing framework. Tests MCP servers against the OWASP MCP Top 10 — both static analysis and live dynamic probing.

Corvus v0.7.0  MCP Security Scanner
Target     : python my_mcp_server.py
Transport  : stdio
Modules    : tool-poisoning, schema-audit, shadow-tool, auth-audit, log-audit,
             param-injection, info-disclosure, schema-bypass, response-flood, rug-pull

Enumerating surface...
  Tools      : 12
  Resources  : 3
  Prompts    : 2
  Server     : my-server 1.0.0

[MCP01] Tool Poisoning (static)
  [HIGH] Potential prompt injection in description of 'execute_code'

[MCP02] Parameter Injection (dynamic)
  [HIGH] Command injection confirmed in tool 'run_shell', param 'command'
  [MEDIUM] Path traversal accepted in tool 'read_file', param 'path'

...

─── Summary ──────────────────────────────────────────────────────────────────
  CRITICAL  0   HIGH  2   MEDIUM  1   LOW  3   INFO  4
  Session   : corvus-sessions/20260608-143022/

Install

pip install cobaltosec-corvus

Or from source:

git clone https://github.com/CobaltoSec/corvus
cd corvus
pip install -e ".[dev]"

Quick Start

# Scan a stdio MCP server
corvus scan --transport stdio --cmd "python my_server.py"

# Scan an HTTP MCP server
corvus scan --transport http --url http://localhost:8080

# With authentication header
corvus scan --transport http --url http://localhost:8080 --header "Authorization: Bearer token"

# Static analysis only (no live tool calls)
corvus scan --transport stdio --cmd "python my_server.py" --module static

# Specific module
corvus scan --transport stdio --cmd "python my_server.py" --module param-injection

# SARIF output (for CI/CD integration)
corvus scan --transport stdio --cmd "python my_server.py" --sarif

# Fail CI on findings above threshold
corvus scan --transport stdio --cmd "python my_server.py" --fail-on high

# Load config from file
corvus scan --config corvus.toml

# Filter low-confidence findings (0-100)
corvus scan --transport stdio --cmd "python my_server.py" --min-confidence 70

# Capture raw JSON-RPC exchanges
corvus scan --transport stdio --cmd "python my_server.py" --log-requests

# List available modules
corvus list-modules

Batch Scan

Scan multiple MCP servers in one invocation:

# targets.yaml
targets:
  - name: filesystem
    transport: stdio
    cmd: ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

  - name: my-http-server
    transport: http
    url: http://localhost:8080
corvus batch targets.yaml --output-dir results/ --sarif --min-confidence 70

Produces a per-target report.json and a top-level summary.md table.

Modules

Full coverage of OWASP MCP Top 10:

Name OWASP Type What it tests
tool-poisoning MCP01 static Hidden instructions, obfuscation, and prompt injection patterns in tool descriptions
param-injection MCP02 dynamic Command, path, prompt, and SQL injection payloads per parameter — schema-aware
shadow-tool MCP03 static Tool names that shadow built-ins or signal dangerous operations (namespace squatting, trust hijacking)
info-disclosure MCP04 dynamic Credentials, filesystem paths, stack traces, and tokens leaked in tool responses
schema-bypass MCP05 dynamic Whether tools properly reject inputs that violate their declared schema
rug-pull MCP06 dynamic Re-enumerates the server after dynamic testing; diffs against initial snapshot to detect added, removed, or mutated tools
response-flood MCP07 dynamic Excessively large or highly repetitive responses that could overflow an LLM context window or inject looping instructions
auth-audit MCP08 static Tool names and descriptions suggesting missing, optional, or bypassable authentication
schema-audit MCP09 static Weak schema definitions (missing required fields, unconstrained types) that expand the attack surface
log-audit MCP10 static Tools that expose or tamper with audit logs — enables anti-forensic techniques or leaks operational data

Module groups

# All modules (default)
--module all

# Static only (no live calls to the server)
--module static

# Dynamic only
--module dynamic

# Individual module
--module param-injection

Transports

stdio

Spawns the server process and communicates via stdin/stdout. Supports any command:

corvus scan --transport stdio --cmd "python server.py"
corvus scan --transport stdio --cmd "npx @modelcontextprotocol/server-filesystem /tmp"
corvus scan --transport stdio --cmd "uvx my-mcp-server --arg value"

HTTP

Connects to a running HTTP/SSE MCP server:

corvus scan --transport http --url http://localhost:8080

# With auth
corvus scan --transport http --url http://localhost:8080 --header "Authorization: Bearer $TOKEN"
corvus scan --transport http --url http://localhost:8080 --header "X-API-Key: secret"

Config File

Create corvus.toml to avoid repeating CLI flags:

[scan]
transport = "stdio"
cmd = "python my_server.py"
modules = "all"
timeout = 30
sarif = false
fail_on = "high"

[scan.headers]
"Authorization" = "Bearer my-token"

Then run:

corvus scan --config corvus.toml

CLI flags override config file values. The --config flag also accepts absolute paths.

CLI Reference

Usage: corvus scan [OPTIONS]

 Scan an MCP server for security vulnerabilities.

Options:
  -t, --transport  TEXT     stdio | http  (overrides config)
  --cmd            TEXT     Command to launch MCP server (stdio)
  --url            TEXT     URL of MCP server (http)
  -m, --module     TEXT     all | static | dynamic | <module-name>  (overrides config)
  -o, --output-dir PATH
  --fail-on        TEXT     Exit 1 if findings at this severity or above
                            (critical|high|medium|low)
  --timeout        INTEGER  Request timeout in seconds (overrides config)
  --sarif                   Also write SARIF 2.1.0 report
  --header         TEXT     HTTP header "Key: Value" (repeatable, for http transport)
  -c, --config     PATH     Path to corvus.toml config file
  --plugin-dir     TEXT     Directory to load external modules from (repeatable)
  --help                    Show this message and exit.

Other commands:

corvus list-modules              # list available modules with OWASP ID and type
corvus list-modules --plugin-dir ./plugins/   # include external plugins
corvus version                   # print version

Output

Each scan creates a session directory under corvus-sessions/<timestamp>/:

corvus-sessions/20260608-143022/
├── report.json     # full structured result
├── report.md       # human-readable with remediation guidance
└── report.sarif    # SARIF 2.1.0 (only when --sarif is passed)

SARIF integration

SARIF output is compatible with GitHub Advanced Security, VS Code SARIF Viewer, and any CI pipeline that consumes SARIF:

# GitHub Actions example
- name: Run Corvus
  run: corvus scan --transport stdio --cmd "python server.py" --sarif --fail-on high

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: corvus-sessions/

CI Integration

# Exit 1 if any CRITICAL findings
corvus scan --transport stdio --cmd "python server.py" --fail-on critical

# Exit 1 if any HIGH or above
corvus scan --transport stdio --cmd "python server.py" --fail-on high

Severity levels (ascending): infolowmediumhighcritical

Plugin System

Add custom modules without modifying Corvus source.

Directory-based plugins

corvus scan --transport stdio --cmd "python server.py" --plugin-dir ./my-modules/

Each .py file in the directory is loaded as a module. The file must define a class that inherits from BaseModule:

from corvus.modules.base import BaseModule, Finding, Severity

class MyCustomModule(BaseModule):
    name = "my-check"
    owasp_id = "MCP-CUSTOM"
    module_type = "static"
    description = "Custom check for my organization"

    async def run(self, surface, transport):
        findings = []
        for tool in surface.tools:
            if "dangerous_pattern" in tool.description:
                findings.append(Finding(
                    rule_id="MY001",
                    tool_name=tool.name,
                    severity=Severity.HIGH,
                    title="Dangerous pattern detected",
                    description=f"Tool '{tool.name}' contains a dangerous pattern.",
                    remediation="Remove or sanitize the pattern.",
                ))
        return findings

Package-based plugins

Register via pyproject.toml entry points:

[project.entry-points."corvus.modules"]
my-check = "my_package.modules.my_check:MyCustomModule"

After pip install my-package, Corvus auto-discovers the module.

Development

git clone https://github.com/CobaltoSec/corvus
cd corvus
pip install -e ".[dev]"
pytest

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cobaltosec_corvus-0.7.0.tar.gz (47.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cobaltosec_corvus-0.7.0-py3-none-any.whl (48.7 kB view details)

Uploaded Python 3

File details

Details for the file cobaltosec_corvus-0.7.0.tar.gz.

File metadata

  • Download URL: cobaltosec_corvus-0.7.0.tar.gz
  • Upload date:
  • Size: 47.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for cobaltosec_corvus-0.7.0.tar.gz
Algorithm Hash digest
SHA256 7e568e31daf228e83d6b1c4df2b96e98745676188ea31d04b7f8503f273d414b
MD5 b801764b8f74185172cc8db6510522cb
BLAKE2b-256 32f9a220884fad5e73eb564eb285240a90d2e7f2d6a40799bfdda230c54cd5b9

See more details on using hashes here.

File details

Details for the file cobaltosec_corvus-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for cobaltosec_corvus-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ab9fa1191231f7490430f55a9432f4162c22fcfb49cdd77d0d4ac1148fb83f4c
MD5 97ee223185d06d6e5a18a666c1866d3b
BLAKE2b-256 377f8be661d01cebcf3aa4a7244781fb95a330a66885f19d74100d5f738e0a08

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page