Skip to content

[BUG]: ToolUpdate.validate_description missing forbidden-pattern check present in ToolCreate #3773

@crivetimihai

Description

@crivetimihai

Bug Description

ToolCreate.validate_description enforces a forbidden-pattern check (shell/pipe metacharacters: &&, ;, ||, $(, |, > , < ) gated behind VALIDATION_STRICT. However, ToolUpdate.validate_description has no such check at all — it only performs length truncation and sanitize_display_text().

This means a tool registered with a safe description can later have its description updated to include shell metacharacters, bypassing the validation that was enforced at creation time.

Reproduction Steps

  1. Register a tool with a safe description (passes ToolCreate validation)
  2. Update the tool's description via PUT/PATCH to include $(malicious) or cmd1 && cmd2
  3. The update succeeds without any warning or rejection, regardless of VALIDATION_STRICT

Expected Behavior

ToolUpdate.validate_description should apply the same forbidden-pattern check as ToolCreate.validate_description, gated by settings.validation_strict.

Root Cause

File: mcpgateway/schemas.py

ToolCreate.validate_description (around line 526) has:

forbidden_patterns = ["&&", ";", "||", "$(", "|", "> ", "< "]
for pat in forbidden_patterns:
    if pat in v:
        if settings.validation_strict:
            raise ValueError(f"Description contains unsafe characters: '{pat}'")
        logger.warning(...)
        break

ToolUpdate.validate_description (around line 1043) only does:

if len(v) > SecurityValidator.MAX_DESCRIPTION_LENGTH:
    truncated = v[: SecurityValidator.MAX_DESCRIPTION_LENGTH]
    ...
return SecurityValidator.sanitize_display_text(v, "Description")

No other *Update schema classes have the check either, but ToolCreate is the only *Create class that does, so the gap is specifically between ToolCreate and ToolUpdate.

Proposed Fix

Extract the forbidden-pattern check into a shared helper (or inline it into ToolUpdate.validate_description) so both create and update paths enforce the same validation. The check should remain gated by settings.validation_strict.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiREST API Related itembugSomething isn't workingsecurityImproves securitytriageIssues / Features awaiting triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions