Forty-two CVEs mentioning MCP were published between 2026-08-25 and
2026-09-01. Nine at CVSS 9.0 or above, two at 10.0. I wrote up why that
shape is what it is [in the companion piece]. This post is the runnable
half: a check you can point at your own MCP server today.
No dependencies beyond Python 3 and ripgrep. It is deliberately dumb, it is
deliberately readable, and it will produce false positives. That is the
correct trade for a ten-minute check.
What it looks for
Four things, each of which is a real advisory from that window.
-
A listen address bound to every interface.
CVE-2026-81735andCVE-2026-82456, both CVSS 10.0, are both this. -
A missing Host or Origin check on an HTTP transport.
CVE-2026-81092in mcp-go: "accepted requests on its HTTP transports without checking the Host header." -
An origin check written with
startswith. Which passeslocalhost.evil.example. Three PraisonAI advisories in that batch. -
An upstream reference pinned to a branch instead of a digest.
CVE-2026-82021, CVSS 9.0, in Hermes Agent's bundled MCP catalog.
The script
Save as mcp_default_check.py, run it against your repo root.
#!/usr/bin/env python3
"""Ten-minute check for the four MCP transport defaults behind most of the
2026-08-25..2026-09-01 CVE batch. Noisy on purpose. Read every hit."""
import re, subprocess, sys, pathlib
ROOT = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
CHECKS = [
("bind-all-interfaces",
r'(0\.0\.0\.0|"::"|\bhost\s*=\s*["\']0\.0\.0\.0)',
"Listening on every interface. CVE-2026-81735 and CVE-2026-82456 "
"(both CVSS 10.0) are this exact default."),
("origin-startswith",
r'\.startswith\(\s*(allowed|origin|ALLOWED)',
"Prefix match used as an origin check. localhost.evil.example passes."),
("branch-pinned-upstream",
r'(@main\b|@master\b|ref\s*[:=]\s*["\'](main|master)["\'])',
"Upstream referenced by mutable branch, not by digest. CVE-2026-82021."),
]
HOST_CHECK = r'(Host\b.*header|check_host|host_header|validate_host|allowed_hosts)'
def rg(pattern, root):
try:
out = subprocess.run(
["rg", "-n", "--no-heading", "-e", pattern, str(root)],
capture_output=True, text=True, timeout=60)
return [l for l in out.stdout.splitlines() if l.strip()]
except FileNotFoundError:
sys.exit("ripgrep (rg) not found. brew install ripgrep / apt install ripgrep")
findings = 0
for name, pat, why in CHECKS:
hits = rg(pat, ROOT)
if hits:
findings += len(hits)
print(f"\n[{name}] {len(hits)} hit(s)\n {why}")
for h in hits[:12]:
print(" ", h[:160])
# Absence check: does an HTTP transport exist with no Host validation anywhere?
serves_http = rg(r'(streamable_http|SSEServer|sse_server|app\.run\(|uvicorn)', ROOT)
host_guard = rg(HOST_CHECK, ROOT)
if serves_http and not host_guard:
findings += 1
print(f"\n[missing-host-check] an HTTP transport is present "
f"({len(serves_http)} hit(s)) and no Host-header validation was found.")
print(" CVE-2026-81092: a loopback connection is not an authenticated one.")
print(f"\n{findings} finding(s). None of these are exploits on their own. "
f"Read each one and decide.")
sys.exit(1 if findings else 0)
Running it
git clone https://github.com/<you>/<your-mcp-server> && cd $_
python3 mcp_default_check.py .
Output on a server with the bind default wrong:
[bind-all-interfaces] 2 hit(s)
Listening on every interface. CVE-2026-81735 and CVE-2026-82456
(both CVSS 10.0) are this exact default.
src/server.py:41: host = os.getenv("HOST", "0.0.0.0")
docker-compose.yml:12: - "0.0.0.0:8080:8080"
[missing-host-check] an HTTP transport is present (3 hit(s)) and no
Host-header validation was found.
CVE-2026-81092: a loopback connection is not an authenticated one.
3 finding(s). None of these are exploits on their own. Read each one and decide.
What it will get wrong
It greps. It has no idea whether the 0.0.0.0 it found is in production
code, a test fixture, or a comment. It cannot tell a Host check that exists
under a name it does not recognise. And a clean run means the four patterns
did not match, not that the server is secure.
Wire it into CI as a warning, not a gate, until you have read enough of its
output to trust it.
Where to go after ten minutes
If you want this maintained rather than pasted, I keep a static scanner for
MCP-connected agent pipelines with a transport-security rule family and a
public CVE-to-rule ledger: agent-audit-kit on PyPI, MIT licensed. One
honest caveat, because it matters for this specific article: the rule
covering CVE-2026-82456 is written and merged but not yet on PyPI at the
time of writing. pip install agent-audit-kit gets you the DNS-rebinding
and no-auth-server rules today. Check the changelog for the rest rather than
taking my word for which version has what.
The query
Reproduce the count yourself. No key needed.
https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=MCP&pubStartDate=2026-08-25T00:00:00.000&pubEndDate=2026-09-01T00:00:00.000
Top comments (0)