Every rule Aevrin runs, what it detects, and how a server is graded.
Aevrin scans MCP servers and the agents that install them. It is not a general-purpose
source-code scanner: there are no findings about Dockerfile style, CI configuration, branch
protection, repository badges, or fuzzing status. If your MCP server's repository also has an
unrelated bug in its web handler, Aevrin will not tell you about it.
Every finding comes from one engine, run against a live server. Aevrin starts the server,
completes the MCP handshake, reads what it offers, and analyses that. A repository is only ever a
way of finding out which server to start - it is not itself the thing being assessed.
A finding is usually about one tool, but it does not have to be. It can also be about a prompt,
the server as a whole, the way it is configured and launched, its code, or one of its
dependencies. Those findings name no tool.
The engine has 75 rules. Each rule id reads MCP-<GROUP>-NNN, and the group says what kind of
problem it is.
| Group | Rules | What it covers |
|---|
MCP-AUTH | 3 | A remote server's transport, login and credentials in its URL |
MCP-CFG | 5 | How the server is configured, installed and launched |
MCP-DEP | 4 | The packages it depends on: malicious, typosquatted, install scripts, loose versions |
MCP-DYN | 7 | What the server does while it runs. Not run today: see Deliberate limits |
MCP-EXEC | 4 | Running commands or code, and unsafe deserialization |
MCP-FS | 4 | Reading, changing and deleting files, and file paths |
MCP-INJ | 5 | Hidden or instruction-shaped text aimed at the agent |
MCP-NET | 3 | Network requests and where they go |
MCP-PERM | 3 | Broad or dangerous combinations of capabilities |
MCP-POISON | 7 | Tool metadata that tries to steer, hide from, or take data from the agent |
MCP-PRIV | 2 | Asking for, or running with, elevated rights |
MCP-PROTO | 5 | How the server speaks the MCP protocol |
MCP-QUALITY | 5 | Missing, loose or misleading tool definitions |
MCP-SCOPE | 2 | A tool doing more than it says it does |
MCP-SECRET | 6 | Secrets exposed, hardcoded, requested or read from the environment |
MCP-SHADOW | 4 | One tool or server standing in for another |
MCP-SQL | 2 | Raw SQL and SQL built from tool input |
MCP-SRC | 4 | Hidden or hostile code in the server itself |
A rule has no fixed severity. The engine sets the severity of each finding when it reports it,
so the same rule can produce findings of different severities. The OWASP column below is the
OWASP MCP Top 10 category Aevrin files each rule under.
| Rule | Title | OWASP |
|---|
| MCP-AUTH-001 | Remote server uses plain HTTP | MCP06 |
| MCP-AUTH-002 | Remote server with powerful tools needs no login | MCP06 |
| MCP-AUTH-003 | Credentials in the server URL | MCP01 |
| Rule | Title | OWASP |
|---|
| MCP-CFG-001 | Server package version is not pinned | MCP07 |
| MCP-CFG-002 | Server is launched through a shell | MCP05 |
| MCP-CFG-003 | Server is installed from a URL or git repository | MCP07 |
| MCP-CFG-004 | Docker image is not pinned | MCP07 |
| MCP-CFG-005 | Config sets environment variables that change how programs run | MCP05 |
| Rule | Title | OWASP |
|---|
| MCP-DEP-001 | Known malicious package | MCP07 |
| MCP-DEP-002 | Package name looks like a typo of a popular package | MCP07 |
| MCP-DEP-003 | Package runs a script when installed | MCP07 |
| MCP-DEP-004 | Dependency from a URL or with any version | MCP07 |
| Rule | Title | OWASP |
|---|
| MCP-DYN-001 | Server leaked a planted secret | MCP01 |
| MCP-DYN-002 | Tools changed during the session | MCP04 |
| MCP-DYN-003 | Tools changed since the last scan | MCP04 |
| MCP-DYN-004 | Server started a shell or network program | MCP05 |
| MCP-DYN-005 | Server made outside network connections | MCP09 |
| MCP-DYN-006 | Server wrote to sensitive files | MCP05 |
| MCP-DYN-007 | Server hit a sandbox limit | MCP09 |
| Rule | Title | OWASP |
|---|
| MCP-EXEC-001 | Tool can run any command or code | MCP05 |
| MCP-EXEC-002 | Tool input reaches a system command | MCP05 |
| MCP-EXEC-003 | Tool input reaches eval or exec | MCP05 |
| MCP-EXEC-004 | Unsafe deserialization | MCP05 |
| Rule | Title | OWASP |
|---|
| MCP-FS-001 | Tool can change or delete files | MCP09 |
| MCP-FS-002 | Tool can read files at any path | MCP05 |
| MCP-FS-003 | Tool input is used as a file path without a folder check | MCP05 |
| MCP-FS-004 | Code touches secret files | MCP01 |
| Rule | Title | OWASP |
|---|
| MCP-INJ-001 | Text tries to override the agent's instructions | MCP02 |
| MCP-INJ-002 | Invisible characters hide text | MCP02 |
| MCP-INJ-003 | Encoded text hidden in metadata | MCP02 |
| MCP-INJ-004 | Runtime content contains instructions for the agent (not run today) | MCP08 |
| MCP-INJ-005 | Terminal control characters in metadata | MCP02 |
| Rule | Title | OWASP |
|---|
| MCP-NET-001 | Tool can request any URL | MCP05 |
| MCP-NET-002 | Code sends data to a data collection service | MCP09 |
| MCP-NET-003 | Tool input decides where a network request goes | MCP05 |
| Rule | Title | OWASP |
|---|
| MCP-PERM-001 | Server can both read private data and send data out | MCP09 |
| MCP-PERM-002 | Server offers many kinds of high risk actions | MCP09 |
| MCP-PERM-003 | Tool sends messages to any recipient | MCP09 |
| Rule | Title | OWASP |
|---|
| MCP-POISON-001 | Hidden order tags in metadata | MCP02 |
| MCP-POISON-002 | Metadata tells the agent to hide things from the user | MCP02 |
| MCP-POISON-003 | Metadata asks for sensitive files | MCP02 |
| MCP-POISON-004 | Metadata asks for conversation data or secrets | MCP02 |
| MCP-POISON-005 | Parameter collects the agent's private context | MCP02 |
| MCP-POISON-006 | Metadata pushes the agent to call this tool | MCP02 |
| MCP-POISON-007 | Metadata describes sending data to an outside place | MCP02 |
| Rule | Title | OWASP |
|---|
| MCP-PRIV-001 | Metadata asks for admin rights or to bypass security | MCP03 |
| MCP-PRIV-002 | Server is launched with elevated rights | MCP09 |
| Rule | Title | OWASP |
|---|
| MCP-PROTO-001 | Server asked the client for extra powers | MCP03 |
| MCP-PROTO-002 | Server writes non-protocol text to its output | MCP09 |
| MCP-PROTO-003 | SSE server points the client to another host | MCP03 |
| MCP-PROTO-004 | Server sent too much data | MCP09 |
| MCP-PROTO-005 | Server uses an old protocol version | MCP09 |
| Rule | Title | OWASP |
|---|
| MCP-QUALITY-001 | Tool has no description | MCP02 |
| MCP-QUALITY-002 | Tool input schema is loose | MCP09 |
| MCP-QUALITY-003 | Tool description is very long | MCP02 |
| MCP-QUALITY-004 | Server lists the same tool name twice | MCP03 |
| MCP-QUALITY-005 | Risky tool has no safety annotations | MCP09 |
| Rule | Title | OWASP |
|---|
| MCP-SCOPE-001 | Tool code does something its description does not mention | MCP09 |
| MCP-SCOPE-002 | Tool annotations do not match what the tool does | MCP09 |
| Rule | Title | OWASP |
|---|
| MCP-SECRET-001 | Secret exposed to the agent | MCP01 |
| MCP-SECRET-002 | Plain text secret in the MCP client config | MCP01 |
| MCP-SECRET-003 | Hardcoded secret in source code | MCP01 |
| MCP-SECRET-004 | Tool asks the agent for a secret | MCP01 |
| MCP-SECRET-005 | Code reads the whole environment | MCP01 |
| MCP-SECRET-006 | Tool hands environment variables to the agent | MCP01 |
| Rule | Title | OWASP |
|---|
| MCP-SHADOW-001 | Metadata gives orders about another tool | MCP03 |
| MCP-SHADOW-002 | Metadata redirects messages to a fixed address | MCP03 |
| MCP-SHADOW-003 | Tool name is also used by another server | MCP03 |
| MCP-SHADOW-004 | Tool name uses lookalike characters | MCP03 |
| Rule | Title | OWASP |
|---|
| MCP-SQL-001 | Tool runs raw SQL | MCP05 |
| MCP-SQL-002 | SQL built from tool input | MCP05 |
| Rule | Title | OWASP |
|---|
| MCP-SRC-001 | Code runs hidden, decoded code | MCP07 |
| MCP-SRC-002 | Code opens a reverse shell | MCP07 |
| MCP-SRC-003 | Code touches startup files | MCP07 |
| MCP-SRC-004 | Tool input is used as a template | MCP05 |
Repository security is not MCP security, and mixing the two buried the findings that matter.
Aevrin does not report on a repository as a whole: no dependency CVEs across its whole tree, and
nothing about Dockerfiles, CI configuration, branch protection or repository badges. Where a rule
reads code or packages, it asks an MCP question about the server being scanned, such as whether
tool input reaches a system command (MCP-EXEC-002).
Supply-chain coverage comes from the MCP-DEP rules (a known malicious package, a typosquatted
name, an install script, a loose dependency) and the MCP-CFG rules about how the server is
installed (an unpinned package or Docker image, an install from a URL or git repository). None of
the 75 rules looks up published vulnerabilities (CVEs) in dependencies.
Every finding carries the specific facts that made its rule fire: where it was found and what
matched. It also explains itself: why it matters, how it could be used against you, and how to
fix it.
The engine checks its own findings. A finding it marks as a likely false positive, or suppresses,
adds nothing to its score, and Aevrin drops it from the report.
Identical verdicts from one rule across several tools are shown as one finding with every
affected tool listed. A server with twenty-four tools that all lack safety annotations has one
problem, not twenty-four. Critical findings are never grouped: a critical is read individually,
by name. A finding about several tools at once, or about no tool, is shown as it is. Grouping
changes how the report reads, never the grade.
A scan has five stages, and each one is a real step:
- Resolving - work out the command that starts this server.
- Launching - start it, in an isolated container.
- Enumerating - complete the MCP handshake and read its tools.
- Analyzing - run the rules over what was read.
- Grading - the engine grades the whole server, and Aevrin writes the summary.
A scan that stops at any of them is incomplete and receives no grade at all, with the
reason attached. A server that will not start, or that returns no tools, has not been shown to
be safe: it has not been assessed. See Concepts.
The grade is for the whole server, not for each tool, because you install the whole server.
The engine works out a risk score from 0 to 100, where higher is worse, and turns it into a
letter: A at 0, B below 15, C below 35, D below 60, F at 60 or more. An F also
needs at least one validated high or critical finding; a high score alone is not enough. See
Risk score and grade.
- Only servers that can actually be started can be graded. A server needing API keys, a browser,
or a private registry is reported as unassessed rather than guessed at.
- Dynamic checks are off today. The engine does not call a server's tools, so nothing is
tested at run time: the MCP-DYN rules and MCP-INJ-004 never fire. A tool whose
description and code look unremarkable but which misbehaves when called is outside what this
scan can see.
- That includes prompt injection in live tool responses (MCP08). Aevrin does not test it, and
every report says so explicitly.
- A grade describes one version at one moment. Reinstalling later can get different code.
Aevrin records these as limitations; it does not manufacture coverage for tests that did not run.