Skip to content

Security Audit: Unconstrained string parameters across all official servers #3537

Closed as not planned

Description

@manja316

Summary

I ran automated security audits on 7 official MCP servers using mcp-security-audit. All servers scored Grade A or B (85-100/100), which is great. But there's one consistent finding across every server except mcp-server-fetch:

No string parameters use maxLength, pattern, or enum constraints.

Findings

Server Score Unconstrained Strings
Fetch 100/100 0
SQLite 95/100 5 (SQL queries, table names)
Time 95/100 4 (timezone identifiers)
GitHub 94/100 Multiple
Memory 92/100 1 (search query)
Git 90/100 18 (paths, messages, branches)
Filesystem 85/100 Multiple (paths)

Why this matters

  1. DoS vector — Unconstrained strings accept arbitrarily long input. A 10MB commit message or 50K-char file path must be processed by the server.
  2. No boundary validation — If an LLM is compromised via prompt injection, the tool schema provides no defense against malformed input.
  3. Network transports — With MCP supporting Streamable HTTP, servers may be network-exposed where these constraints become critical.

Suggested fix

One line per parameter:

{
  "name": "path",
  "type": "string",
  "maxLength": 4096
}

For known-format params:

{
  "name": "timezone",
  "type": "string",
  "pattern": "^[A-Za-z_/]+$",
  "maxLength": 50
}

Full reports

Individual JSON/text reports for each server: LuciferForge/mcp-audit-reports

The audit tool: pip install mcp-security-audit

Happy to discuss findings or help with fixes.

Activity

  1. razashariff commented on Mar 16, 2026

    @razashariff

    MCPS (MCP Secure) solves this at the message layer — every JSON-RPC body is SHA-256 hashed and ECDSA P-256 signed before transmission. A compromised proxy can't inject malformed parameters because the signature covers the full message body. Nonce + timestamp binding prevents replay. Designed as a drop-in security layer for MCP servers. IETF Internet-Draft | github.com/razashariff/mcps

  2. joergmichno commented on Mar 21, 2026

    @joergmichno

    Good findings. The unconstrained string issue is real, and schema-level constraints (maxLength, pattern, enum) would help with the DoS vector.

    But there's a deeper problem: even with schema constraints in place, the content of those strings can still carry prompt injection payloads. A maxLength: 500 parameter still has room for "Ignore previous instructions and..." — the constraint prevents oversized input but not malicious input.

    We've been looking at this from the content analysis side with ClawGuard (open-source, regex-based MCP scanner). Some data points:

    • A peer-reviewed study (Queen's University, 1,899 MCP servers) found 5.5% are susceptible to Tool Poisoning — where tool descriptions themselves contain hidden behavioral directives
    • System prompt restrictions ("don't follow injected instructions") reduce attack success rate by only 0.65% — essentially useless as a defense
    • The git server's 18 unconstrained strings are particularly concerning because commit_message and branch_name parameters are user-controlled in collaborative workflows

    Schema constraints + content scanning are complementary layers. Neither alone is sufficient.

  3. khalidsaidi commented on Mar 25, 2026

    @khalidsaidi
  4. piiiico commented on Apr 3, 2026

    @piiiico
  5. pshkv commented on Apr 4, 2026

    @pshkv
  6. hidearmoon commented on Apr 17, 2026

    @hidearmoon
  7. kinthaiofficial commented on Apr 28, 2026

    @kinthaiofficial
  8. piiiico commented on Apr 28, 2026

    @piiiico
  9. ppcvote commented on Apr 29, 2026

    @ppcvote
  10. ppcvote commented on Apr 30, 2026

    @ppcvote
  11. jashshah999 commented on May 5, 2026

    @jashshah999
  12. PengSpirit commented on May 9, 2026

    @PengSpirit
  13. xlyoung commented on Jun 6, 2026

    @xlyoung
  14. feiiiiii5 commented on Aug 18, 2026

    @feiiiiii5

    I'd like to take the memory server part of this audit.

    Proposed change (ready locally, small diff):

    • Add maxLength to search_nodes' query parameter via a named constant (SEARCH_QUERY_MAX_LENGTH = 2048) and an exported SearchNodesQuerySchema, following the pattern in Add schema constraints to time server strings #4282 (time server string constraints).
    • Vitest coverage for the boundary: normal query accepted, at-limit accepted, over-limit rejected, non-string still rejected.

    Scope kept to query as named in the audit's memory-server finding; remaining parameters can be separate follow-ups. Happy to adjust the limit value or shape if maintainers prefer.

  15. DSHCorrectover commented on Aug 23, 2026

    @DSHCorrectover
  16. DSHCorrectover commented on Aug 24, 2026

    @DSHCorrectover
  17. Paraphern commented on Oct 12, 2026

    @Paraphern

    The audit and the enforcement discussion address the current state well: constraints are missing (the audit), they are advisory not enforced (pshkv), guardrails enforce them at call time (piiiico), and tool descriptions are the model's decision surface (PengSpirit). One dimension no comment has addressed: what happens when the constraints themselves change between releases?

    A server that adds maxLength: 2048 to a string parameter today has closed one gap. But in the next release: the constraint can be removed (the gap returns silently), the parameter can be renamed (the constraint is orphaned), or a new unconstrained parameter can appear (a new gap nobody audited). The audit in this issue is a point-in-time assessment — valuable, but it decays the moment any official server ships a new version.

    The missing layer is a surface pin: hash each tool's full definition (name, description, inputSchema, annotations) at a known-good baseline, and diff on every subsequent release. A removed constraint flags as LOOSENED (the DoS vector is back). A new unconstrained parameter flags as NEW (needs the same audit applied to the old set). A tightened constraint flags as BREAKING (callers may now fail). And serialization churn flags as NOTATION — not a finding, not an alert.

    In production monitoring across 14 public MCP servers, one recent vendor major changed all 20 pinned tools in one release: 15 were pure serialization churn, 5 were real constraint tightenings. Without grading, the 5 real findings sat in a 20-line alert wall. With grading, the signal is clean.

    The official servers in this repo are the canonical reference implementations. If they shipped with a committed pin file (hashes of each tool's definition at each tagged release), downstream servers could diff against them the same way package managers verify checksums — and audits like this one would become continuous rather than point-in-time.

    We ship the pin-and-graded-diff layer open-source (rugsnare, Apache-2.0); per-version drift records for 14 public MCP servers: https://github.com/Paraphern/rugsnare/tree/main/docs/servers

  18. cliffhall commented on Oct 19, 2026

    @cliffhall
    Member

    Triage: Priority Low (total 4)

    • Severity 1, urgency 1
    • Bonuses: +1 concerns security, +1 high engagement

    This is a security report, so it is handled by the maintainers and the details aren't discussed here. If you have more to add, please use the advisory form rather than this thread.

    Board: Servers V2 (#43), Status Incoming, awaiting maintainer review (no milestone yet). Part of the backlog triage in #4875.

  19. modified the milestones: v2.3.0, v2.4.0 on Oct 25, 2026
  20. cliffhall commented on Nov 5, 2026

    @cliffhall
    Member

    Thank you for the audit, and to everyone who added to the thread. Re-checking it against the current code on v2/main, I'm closing this as not planned:

    If you find a specific input on one of these servers that causes harm through its size or format, please open an issue for that case with steps to reproduce, or report it through the advisory form if it's a vulnerability.

  21. removed this from the v2.4.0 milestone on Nov 5, 2026
  22. Paraphern commented on Nov 5, 2026

    @Paraphern

    Thanks for the detailed re-check and for separating the already-addressed findings from the cases that need runtime-specific evidence.

    Understood on the scope and the decision to close this issue. We'll treat the current findings as resolved or out of scope here, and use the appropriate issue or private advisory channel if we identify a concrete, independently reproducible problem.

    Appreciate the careful review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions