Skip to content

[Bug]: Prompt and RPC Endpoints Accept XSS Content Without Validation Error #361

@crivetimihai

Description

@crivetimihai

Prompt Endpoint Accepts XSS Content Without Validation Error

Priority: High (Security/Data Integrity)

Description:
The prompt execution endpoint (/prompts/{prompt_name}) does not validate or reject XSS content in prompt arguments. While the system correctly escapes HTML entities in the output (preventing actual XSS execution), it does not return a validation error for potentially malicious input as expected.

Steps to Reproduce:

  1. Start the MCP Gateway server:

    make serve
  2. Generate authentication token:

    export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token -u admin --secret my-test-key)
  3. Create a test prompt with arguments:

    curl -X POST http://localhost:4444/prompts \
      -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "greeting_prompt",
        "description": "Personalized greeting template",
        "template": "Hello {{ name }}, welcome to {{ company }}!",
        "arguments": [
          {"name": "name", "description": "User name", "required": true},
          {"name": "company", "description": "Company name", "required": true}
        ]
      }'
  4. Execute the prompt with XSS content:

    curl -X POST http://localhost:4444/prompts/greeting_prompt \
      -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Alice<script>alert(1)</script>",
        "company": "Acme Corp"
      }'

Expected Behavior:

  • Should return HTTP 422 (Unprocessable Entity) status code
  • Error message should indicate that prompt arguments contain invalid characters or potential XSS content
  • The request should be rejected before template rendering

Actual Behavior:

  • Returns HTTP 200 with escaped HTML in the response:
    {
      "messages": [{
        "role": "user",
        "content": {
          "type": "text",
          "text": "Hello Alice&lt;script&gt;alert(1)&lt;/script&gt;, welcome to Acme Corp!"
        }
      }],
      "description": "Personalized greeting template"
    }
  • XSS content is escaped but not rejected

Impact:

  • While the current behavior prevents actual XSS execution through escaping, it doesn't follow the principle of input validation
  • Inconsistent with other endpoints that reject XSS attempts with validation errors
  • May allow storage of escaped XSS content in logs or databases
  • Could be problematic if the escaped content is later used in contexts where escaping is not applied

Root Cause Analysis:
The prompt execution endpoint likely lacks input validation for the dynamic arguments passed to prompts. The system is relying solely on output escaping rather than input validation.

Suggested Fix:

  1. Add input validation to the prompt execution endpoint to check for XSS patterns in argument values

  2. Implement validation in the prompt execution handler that checks all argument values:

    from mcpgateway.utils.validators import validate_no_xss
    
    @router.post("/prompts/{prompt_name}")
    async def execute_prompt(prompt_name: str, arguments: Dict[str, Any]):
        # Validate all argument values
        for key, value in arguments.items():
            if isinstance(value, str):
                try:
                    validate_no_xss(value, f"Prompt argument '{key}'")
                except ValueError as e:
                    raise HTTPException(status_code=422, detail=str(e))
        
        # Continue with prompt execution...
  3. Consider making XSS validation configurable:

    • Strict mode: Reject any HTML-like content (current test expectation)
    • Escape mode: Allow but escape (current behavior)
    • This could be controlled via environment variable

Additional Context:

  • This issue was discovered during comprehensive input validation testing
  • Other endpoints (tools, resources, gateways) properly reject XSS with validation errors
  • The inconsistency in validation behavior across endpoints could confuse API users
  • HTML escaping is a good defense-in-depth measure but shouldn't replace input validation

Testing Considerations:

  • Test with various XSS patterns: <script>, <img src=x onerror=>, javascript:, etc.
  • Test with legitimate use cases that might contain angle brackets: mathematical expressions (a < b), email formats
  • Ensure validation doesn't break legitimate template variables

Related Issues:

RPC Endpoint Accepts Invalid Method Names Without Proper Validation

Priority: High (Security/Input Validation)

Description:
The RPC endpoint (/rpc) does not properly validate method names before processing, allowing potentially malicious content (including XSS patterns) in method names. Instead of returning a validation error for invalid method name formats, it processes the request and returns a "Tool not found" error, indicating the invalid input reached the tool lookup logic.

Steps to Reproduce:

  1. Start the MCP Gateway server:

    make serve
  2. Generate authentication token:

    export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token -u admin --secret my-test-key)
  3. Send an RPC request with XSS content in the method name:

    curl -X POST http://localhost:4444/rpc \
      -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "method": "<script>alert(1)</script>",
        "id": 1
      }'

Expected Behavior:

  • Should return HTTP 422 (Unprocessable Entity) or appropriate JSON-RPC error
  • Error response should indicate "Invalid method name format" or similar
  • The method name should be validated before any tool lookup occurs
  • Valid method names should follow pattern: [gateway-name]-[tool-name] or tools/list, resources/list, etc.

Actual Behavior:

  • Returns HTTP 200 with JSON-RPC error indicating the invalid input was processed:
    {
      "jsonrpc": "2.0",
      "error": {
        "code": -32000,
        "message": "Internal error",
        "data": "Tool not found: <script>alert(1)</script>"
      },
      "id": 1
    }
  • The invalid method name reached the tool lookup logic, indicating lack of input validation

Impact:

  • Invalid input is being processed by internal logic rather than rejected at validation layer
  • Potential for injection attacks if method names are used in database queries or logging without proper sanitization
  • Inconsistent with other endpoints that properly validate input
  • Could lead to error messages that leak internal implementation details

Root Cause Analysis:
The RPC handler is not validating the method name format before attempting to process the request. The method name is passed directly to the tool/resource lookup logic without checking if it conforms to expected patterns.

Suggested Fix:

  1. Add method name validation to the RPC endpoint handler:

    import re
    from fastapi import HTTPException
    from mcpgateway.utils.validators import validate_no_xss
    
    # Define valid method patterns
    VALID_METHOD_PATTERNS = [
        r'^[a-zA-Z0-9_-]+-[a-zA-Z0-9_-]+$',  # gateway-tool pattern
        r'^(tools|resources|prompts)/(list|get)$',  # built-in methods
        r'^servers/[a-f0-9-]+/(tools|resources|prompts)/list$'  # server methods
    ]
    
    def validate_rpc_method(method: str) -> bool:
        """Validate RPC method name format"""
        # First check for XSS patterns
        try:
            validate_no_xss(method, "RPC method name")
        except ValueError:
            return False
        
        # Then check against valid patterns
        for pattern in VALID_METHOD_PATTERNS:
            if re.match(pattern, method):
                return True
        return False
    
    @router.post("/rpc")
    async def handle_rpc(request: dict):
        method = request.get("method", "")
        
        if not validate_rpc_method(method):
            return {
                "jsonrpc": "2.0",
                "error": {
                    "code": -32602,  # Invalid params
                    "message": "Invalid method name format",
                    "data": f"Method name must match pattern: [gateway-name]-[tool-name] or built-in methods"
                },
                "id": request.get("id")
            }
        
        # Continue with normal RPC processing...
  2. Consider implementing a method registry or enum for valid built-in methods

  3. Add strict validation for the gateway-tool separator pattern

Additional Context:

  • JSON-RPC 2.0 specification suggests using error code -32602 for invalid parameters
  • Method names should be restricted to alphanumeric characters, hyphens, underscores, and forward slashes for paths
  • This validation should occur before any database lookups or business logic

Testing Considerations:

  • Test with various injection patterns: SQL injection, XSS, command injection
  • Test with valid method names to ensure they still work:
    • time-server-get-system-time
    • tools/list
    • servers/[uuid]/tools/list
  • Test with edge cases: empty string, very long strings, unicode characters
  • Ensure error messages don't leak sensitive information

Security Implications:

  • Current behavior could be exploited for error-based information disclosure
  • Method names might be logged without sanitization
  • Could be part of a larger attack chain if combined with other vulnerabilities

Related Issues:

Metadata

Metadata

Labels

bugSomething isn't workingsecurityImproves securitytriageIssues / Features awaiting triage

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions