{"slug": "how-to-audit-your-mcp-servers-for-security-risks", "title": "How to Audit Your MCP Servers for Security Risks", "summary": "AgentGraph has released an open-source CLI and GitHub Action called mcp-security-scan that audits MCP servers for credential theft, data exfiltration, unsafe execution, and code obfuscation, outputting a 0-100 trust score. The tool addresses the security gap highlighted by the Moltbook breach, where 770,000 agents exposed 35,000 emails and 1.5 million API tokens due to unverified MCP server credentials.", "body_md": "**TL;DR:** MCP servers run with significant privileges inside AI agent pipelines, and most teams ship them without any security review. `mcp-security-scan`\n\nis an open-source CLI and GitHub Action that checks for credential theft patterns, data exfiltration, unsafe execution, and code obfuscation — and outputs a 0-100 trust score that integrates with AgentGraph's identity layer.\n\nThe Moltbook breach last year is still the clearest example of what happens when you scale agent infrastructure without thinking about trust. 770,000 agents, zero identity verification, and when it went down it exposed 35,000 emails and 1.5 million API tokens. The tokens were the real problem — many of them were credentials passed through MCP servers that nobody had audited.\n\nMCP (Model Context Protocol) servers are the connective tissue of modern agent systems. They sit between your LLM and the outside world, handling tool calls, filesystem access, API requests. That position gives them a lot of power. It also makes them an obvious target.\n\nAnd yet most teams treat MCP servers like they treat npm packages circa 2015: install and trust.\n\nBefore getting into the scanner, it's worth being specific about the threat categories. There are four that show up most often in real codebases:\n\n**Credential theft** — MCP servers that read environment variables indiscriminately, log request/response payloads, or forward tool call arguments to external endpoints. This one is subtle because the server might be doing legitimate work *and* exfiltrating credentials.\n\n**Data exfiltration** — Outbound HTTP calls to domains that weren't declared in the server's manifest, or calls that happen inside tool handlers where the LLM can influence the destination URL. Prompt injection into tool parameters is the attack vector here.\n\n**Unsafe execution** — `eval()`\n\n, `exec()`\n\n, `subprocess`\n\ncalls, or dynamic `require()`\n\n/`import()`\n\nwhere the argument comes from tool call input. If an LLM can influence what gets executed, you have a problem.\n\n**Filesystem access** — Path traversal risks, reading outside declared directories, writing to sensitive locations. Especially bad in servers that accept filename parameters from the model.\n\nOpenClaw's skills marketplace has 512 CVEs at last count, and roughly 12% of skills contain what their own security team classifies as malware. That's a marketplace that grew fast and audited slowly.\n\n`mcp-security-scan`\n\n`mcp-security-scan`\n\nis a CLI tool and GitHub Action for scanning MCP server source code and runtime behavior. It's MIT licensed, lives at [github.com/agentgraph-co/mcp-security-scan](https://github.com/agentgraph-co/mcp-security-scan), and produces a structured JSON report plus a 0-100 trust score.\n\nInstall it:\n\n```\nnpm install -g mcp-security-scan\n```\n\nBasic scan against a local server directory:\n\n```\nmcp-security-scan scan ./my-mcp-server\n```\n\nOutput:\n\n```\n{\n  \"score\": 74,\n  \"findings\": [\n    {\n      \"severity\": \"HIGH\",\n      \"category\": \"credential_theft\",\n      \"rule\": \"env-wildcard-read\",\n      \"file\": \"src/tools/search.ts\",\n      \"line\": 43,\n      \"message\": \"process.env spread into tool response object\",\n      \"snippet\": \"return { ...process.env, results }\"\n    },\n    {\n      \"severity\": \"MEDIUM\",\n      \"category\": \"unsafe_execution\",\n      \"rule\": \"dynamic-require\",\n      \"file\": \"src/index.ts\",\n      \"line\": 112,\n      \"message\": \"require() called with non-literal argument\",\n      \"snippet\": \"const mod = require(toolName)\"\n    }\n  ],\n  \"passed\": 18,\n  \"failed\": 2,\n  \"agentgraph_trust_badge\": \"https://agentgraph.co/badge/mcp/...\"\n}\n```\n\nThe score drops from 100 based on finding severity: HIGH findings cost 15 points each, MEDIUM costs 5, LOW costs 1. That's configurable via a `.mcp-scan.json`\n\nfile if your threat model weights things differently.\n\nThe GitHub Action is the more useful integration for teams that ship MCP servers regularly:\n\n```\nname: MCP Security Scan\n\non: [push, pull_request]\n\njobs:\n  security:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Scan MCP Server\n        uses: agentgraph-co/mcp-security-scan@v1\n        with:\n          path: ./server\n          fail-on-severity: HIGH\n          min-score: 70\n          agentgraph-api-key: ${{ secrets.AGENTGRAPH_API_KEY }}\n```\n\nThe `agentgraph-api-key`\n\nis optional. Without it, you get the local scan results. With it, the score gets pushed to your agent's trust profile on [AgentGraph](https://agentgraph.co/?utm_source=agentgraph_bot&utm_medium=devto&utm_campaign=security_scanner), and your README badge updates automatically after each passing scan.\n\n`fail-on-severity: HIGH`\n\nwill exit with code 1 on any HIGH finding, blocking the PR merge. `min-score: 70`\n\ndoes the same if the aggregate score drops below threshold. You can use one, both, or neither depending on how strict you want to be.\n\nThe scan runs in two phases: static analysis and (optionally) dynamic analysis.\n\nStatic analysis uses AST parsing via `@typescript-eslint/parser`\n\nfor TypeScript/JavaScript servers and `ast`\n\nmodule for Python servers. The rules are pattern-based, not ML-based. That was a deliberate call.\n\nML-based detection would catch more subtle patterns, but it would also produce false positives that developers learn to ignore. A rule that says \"flag `process.env`\n\nspread into any object that gets returned from a tool handler\" is specific, auditable, and easy to suppress with a comment when you have a legitimate reason.\n\nEvery rule has a rule ID, a description, and a link to the rationale. If a finding doesn't make sense for your codebase, you suppress it explicitly:\n\n```\n// mcp-scan-disable-next-line env-wildcard-read\nreturn { ...process.env, results }\n```\n\nThat suppression gets logged in the report so reviewers can see what was intentionally skipped.\n\nCurrent rule count: 34 rules across the four categories. The full list is in the repo's `docs/rules.md`\n\n.\n\nDynamic analysis is opt-in and requires Docker. It spins up the MCP server in a sandboxed container with network monitoring enabled, runs a set of synthetic tool calls, and records outbound connections.\n\n```\nmcp-security-scan scan ./my-mcp-server --dynamic\n```\n\nThis catches things static analysis misses: obfuscated code that decodes at runtime, dependencies that phone home, servers that behave differently under specific input patterns.\n\nThe trade-off is obvious: it's slower (adds 30-90 seconds depending on server startup time), requires Docker, and can't catch everything — a server could behave differently with real LLM-generated inputs than with synthetic ones. But it catches the low-hanging fruit reliably.\n\nThe 0-100 score is designed to integrate with AgentGraph's trust infrastructure. AgentGraph assigns W3C DIDs to AI agents and maintains auditable trust scores based on verifiable signals — scan results, deployment history, operator reputation. The scanner is one input into that system.\n\nWhen you push scan results via the API key, they get recorded on-chain as part of the agent's evolution trail. That means you can show users of your MCP server a verifiable history of security scans, not just a static badge that could be faked.\n\nThis is the piece that distinguishes it from running ESLint with some custom rules. ESLint output lives in your CI logs. The trust score lives in a verifiable record that third parties can check before deciding whether to use your server.\n\nA few honest notes on choices that didn't go perfectly:\n\n**The scoring formula is too simple.** Flat point deductions per severity don't capture the difference between a HIGH finding in a core authentication handler versus a HIGH finding in a rarely-called utility function. We're working on a weighted scoring model that factors in code path reachability. The current version errs toward simplicity — a score you can explain beats a score that's accurate but opaque.\n\n**Python support is incomplete.** The TypeScript/JavaScript rules are more mature. Python servers get about 60% of the rule coverage. If you're building Python MCP servers, the scanner will still catch the most common issues, but don't treat a passing score as a clean bill of health.\n\n**Dynamic analysis doesn't handle auth flows well.** If your MCP server requires OAuth or API key setup before it will respond to tool calls, the dynamic scanner will time out waiting for initialization. There's a `--dynamic-init-script`\n\nflag that lets you provide a setup script, but it's clunky. This is on the roadmap.\n\n**The false positive rate on obfuscation detection is ~8%.** Some legitimate minification patterns trigger the obfuscation rules. The fix is usually adding the file to `.mcp-scan-ignore`\n\n, but it's annoying when it hits a vendored dependency you can't control.\n\nIf you're publishing an MCP server publicly — on npm, GitHub, or through a marketplace — the trust badge is the user-facing output of all this.\n\nAfter your first successful scan with an API key, you get a badge URL:\n\n```\n[![MCP Security Score](https://agentgraph.co/badge/mcp/your-server-id)](https://agentgraph.co/agent/your-server-id)\n```\n\nThe badge shows the current score and links to the full scan history. It updates after each scan that pushes results to the API. If a scan fails or the score drops below 70, the badge goes red.\n\nThis is the same trust infrastructure that AgentGraph uses for AI agents more broadly — verifiable DIDs, on-chain audit trails, social graph trust scoring. The scanner is a way into that system for teams who build tooling rather than agents directly.\n\nBeing clear about limitations:\n\n**Supply chain attacks in dependencies.** The scanner checks your code, not your `node_modules`\n\n. Use something like `socket.dev`\n\nor `npm audit`\n\nalongside it for dependency scanning.\n\n**Logic-level vulnerabilities.** If your server correctly implements a tool that does something dangerous by design, the scanner won't flag it. It checks implementation patterns, not intent.\n\n**Runtime prompt injection.** The dynamic analysis catches some injection patterns, but a sophisticated attack that only triggers under specific LLM-generated inputs won't show up in synthetic testing.\n\n**Configuration security.** How you deploy the server, what permissions it runs with, network policies — none of that is in scope.\n\nThink of it as one layer in a defense-in-depth approach, not a complete security solution.\n\n```\n# Install\nnpm install -g mcp-security-scan\n\n# Scan a local server\nmcp-security-scan scan ./path/to/server\n\n# Scan with dynamic analysis\nmcp-security-scan scan ./path/to/server --dynamic\n\n# Output JSON for CI integration\nmcp-security-scan scan ./path/to/server --format json --output report.json\n\n# Check a specific rule\nmcp-security-scan rules list\nmcp-security-scan rules explain env-wildcard-read\n```\n\nThe full documentation is in the repo. Issues and PRs are open — the rule set in particular benefits from real-world examples of patterns people have seen in the wild.\n\nMCP servers are infrastructure. They deserve the same security review you'd give any other piece of infrastructure that touches credentials and runs code on behalf of users. Most teams aren't doing that review today because there wasn't a fast, automated way to do it.\n\n`mcp-security-scan`\n\nis the starting point. It won't catch everything, and the trust score is a signal, not a guarantee. But a score of 45 with three HIGH findings is a concrete thing you can act on before shipping.\n\nThe broader project — verifiable agent identity, auditable trust trails, a trust layer that scales across the agent ecosystem — is what [AgentGraph](https://agentgraph.co/?utm_source=agentgraph_bot&utm_medium=devto&utm_campaign=security_scanner) is building. The scanner is how a lot of developers find their way into it.\n\nRepo: [github.com/agentgraph-co/mcp-security-scan](https://github.com/agentgraph-co/mcp-security-scan)\n\n*Disclosure: This post was generated with AI assistance as part of AgentGraph's content pipeline. The technical details reflect the actual tool's behavior.*", "url": "https://wpnews.pro/news/how-to-audit-your-mcp-servers-for-security-risks", "canonical_source": "https://dev.to/agentgraph/how-to-audit-your-mcp-servers-for-security-risks-5e8a", "published_at": "2026-07-30 00:15:25+00:00", "updated_at": "2026-07-30 00:30:21.410188+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "developer-tools", "ai-infrastructure"], "entities": ["AgentGraph", "Moltbook", "OpenClaw", "mcp-security-scan"], "alternates": {"html": "https://wpnews.pro/news/how-to-audit-your-mcp-servers-for-security-risks", "markdown": "https://wpnews.pro/news/how-to-audit-your-mcp-servers-for-security-risks.md", "text": "https://wpnews.pro/news/how-to-audit-your-mcp-servers-for-security-risks.txt", "jsonld": "https://wpnews.pro/news/how-to-audit-your-mcp-servers-for-security-risks.jsonld"}}