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.8.1.tar.gz (54.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.8.1-py3-none-any.whl (54.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: cobaltosec_corvus-0.8.1.tar.gz
  • Upload date:
  • Size: 54.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.8.1.tar.gz
Algorithm Hash digest
SHA256 a4b92727b126d13e4ecc83da3ad38f648371321a6391af5d46be70169088b4ed
MD5 146f8dcfb7b2b5b76f782549b46f3f66
BLAKE2b-256 a1cdb75196028b996c8a284f2034d6edb85bd0a7e4e95416dac3a762bad9dd92

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for cobaltosec_corvus-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8aa33f3c9599f580d33c7f6a055ccb77673b63ee8399f4e740070ed0f0681fa5
MD5 4e60b4f2d2b6e3a6081b4b1debb8e5f3
BLAKE2b-256 24ce8491ece012fc6dc419ed3a0fb5294186bf77b974500345ce23d316f8b486

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