MCP servers expose tools to LLMs, but most configs grant tools broader permissions than they need, ship without auth, and leak prompt-injection surface in tool descriptions. This scanner finds it before your model does.
Most MCP servers I've audited in the last few months had the same three issues:
- A
shellorfstool was scoped to the entire filesystem when the use case needed exactly one directory. - The transport ran without auth because the local-dev SSE config got promoted to prod.
- Tool descriptions echoed verbatim into prompts with no sanitization — a perfect injection surface.
@hailbytes/mcp-security-scanner is what I wish I'd had on day one of building MCP servers. It's a static + dynamic scanner for MCP configs and live endpoints that flags these patterns.
CLI
# Scan a local config
npx @hailbytes/mcp-security-scanner ./mcp-config.json
# Scan a live endpoint
npx @hailbytes/mcp-security-scanner https://my-mcp-server.example.com
# SARIF output + fail the build
npx @hailbytes/mcp-security-scanner ./config.json --output=sarif --exit-code
Programmatic
import { scan } from "@hailbytes/mcp-security-scanner";
const report = await scan({ configPath: "./mcp-config.json" });
if (!report.passed) {
console.error(report.findings);
process.exit(1);
}
What it checks
- Overprivileged tools — broader permissions than the declared function needs (filesystem scope, shell access, network egress)
- Missing or weak authentication — unauthenticated transports, missing token validation, plaintext secrets in config
- Prompt injection surface — tool descriptions and output paths that pass through to model context without sanitization
- Unsafe defaults — insecure transport defaults, verbose error exposure, CORS wildcards
The SARIF output drops straight into GitHub Code Scanning, so findings show up as alerts on PRs — same place your SAST results live.
npm install -g @hailbytes/mcp-security-scanner
Source: github.com/hailbytes/mcp-security-scanner — MIT licensed. Pairs nicely with @hailbytes/mcp-server-template if you want a scaffold that comes up secure by default.
Top comments (0)