SW-REG-002: MCP server not admitted in the organisation's private registry
Last updated 7 November 2026
| Fact | Value |
|---|---|
| Severity | High |
| Checks | Private registry, in a connected run |
| Malicious indicator | No |
| OWASP Agentic Top 10 | None mapped |
| OWASP MCP Top 10 | MCP09 |
| NIST SP 800-53 | SR-3 (provisional mapping to SP 800-53 base controls) |
| First shipped in | Scanner 1.2.0 |
What it detects
As with the other registry rules, this one has no detector in the scanner's rule code and is never reported by spellwarden scan alone. It needs an organisation on the Enterprise plan and a connected run with the registry check on. Every server with an http or sse transport is judged, and every server with a command is judged when the CI policy judges stdio servers. An entry with neither a command nor a url is not judged.
A remote server is identified by the hash of its normalised address, query included, so the address itself never leaves the runner. A stdio server is identified by the pinned form of its launch: cmd:, the launcher and its packages, then the registries or indexes the launch names, then a 32-character hash of any other argument. The names of the entry's env keys go into the hash, and their values never do. The check identifies a launch only for npx, bunx, pnpm dlx, uvx, pipx run and docker run, with every package at an exact version or an image at a digest.
Each server in scope that the registry does not admit is one finding at the server's line, severity high. The evidence is the server name and the identity, and the report links to the request for admission, whose address carries no user name, query or fragment.
Why it matters
An MCP server is a program that an agent talks to and whose answers the agent reads as input. One that nobody responsible has reviewed can describe its tools with instructions, return text that steers the agent, or receive data that the agent sends it. Judging every added or changed server against the registry before the merge keeps the list of servers that agents can reach an explicit one. The scanner maps this rule to OWASP MCP09, Shadow MCP Servers, and to NIST SP 800-53 control SR-3, Supply Chain Controls and Processes.
The rule needs the Enterprise plan and a connected run. See the registry check of the CI guide for how the check runs and the private registry guide for how the registry admits a server.
Example
A pull request adds the remote server below. The hash of its address is not known to the registry, so a connected run reports it:
This example is an illustration. It cannot be checked offline with spellwarden scan, for the reason given below it.
The rule is applied by a connected run that sends the hash of the server's address to the organisation's private registry (spellwarden_scan/rules/registry.py has no detector), so no offline scan can reproduce it.
.mcp.json
{
"mcpServers": {
"tickets": {
"type": "http",
"url": "https://tools.example.invalid/mcp"
}
}
}The finding sits on the server's line, and its evidence is the server name followed by the identity, which is the hash of the address and not the address itself.
How to fix
Request admission with the link in the report, or remove the server from the change. A remote server is admitted through its scan and the registry's policy; a pinned stdio command is admitted by an allow entry that an administrator adds for that exact launch.
If the launch cannot be identified at all, the finding is SW-REG-003 instead and the first step is to make it identifiable. Pin every package to an exact version and write the command out, so that the registry has one launch to admit.
If it is a false positive
A server that the registry already admits can still be reported when its identity differs: a staging address, a changed query string, an added argument or another name among the env keys each make a new identity. Ask for the new identity to be admitted, or return to the admitted form.
If the finding is not a problem in your case, accept it with a note: in the dashboard a manager or owner can accept a finding and the note is kept with it; with the scanner on its own, add it to the baseline file with a reason and an expiry date.