Skip to content

Feature-221 : Gateway-Level Input Validation & Output Sanitization#1536

Merged
crivetimihai merged 6 commits intomainfrom
feature/security-gateway-io-validation-221
Dec 12, 2025
Merged

Feature-221 : Gateway-Level Input Validation & Output Sanitization#1536
crivetimihai merged 6 commits intomainfrom
feature/security-gateway-io-validation-221

Conversation

@nmveeresh
Copy link
Copy Markdown
Collaborator

@nmveeresh nmveeresh commented Dec 2, 2025

Gateway-Level Input Validation & Output Sanitization

Closes #221

🔒 Security Enhancement

This PR introduces a comprehensive security layer for input validation and output sanitization within the MCP Gateway, significantly reducing the attack surface for path traversal, command injection, and control-character exploits.


🎯 Key Features

1. Path Traversal Defense

  • Normalizes all paths using secure resolvers.
  • Enforces confinement to declared root directories.
  • Blocks attempts like:
    • ../../../etc/passwd
    • ......\windows\system32

2. Parameter Validation

  • Detects and rejects:
  • Shell metacharacters
  • SQL injection patterns
  • XSS-oriented strings
  • Unsafe URLs (javascript:)
  • Control characters (0x00–0x1F, 0x7F–0x9F)

3. Output Sanitization

  • Removes unsafe control characters before delivering responses.
  • Validates MIME types and prevents malicious payloads.

4. Configurable Security Modes

  • Fully feature-flagged via:
  • EXPERIMENTAL_VALIDATE_IO
  • Strict vs warn mode
  • Sanitization toggle

5. System-Wide Coverage

  • New validation middleware applied early in request lifecycle.
  • Safe wrapper for subprocess execution.
  • Updated resource service path normalization.
  • Sanitization pipeline for responses.

🛠️ Implementation Details

New Components

  • Request validation middleware
  • Secure path normalization utility
  • Sanitized response generator
  • Safe subprocess command executor

Updated Components

  • Resource service
  • Tool execution pipeline
  • Global configuration manager

🔧 Configuration Added (in .env)

EXPERIMENTAL_VALIDATE_IO=false
VALIDATION_MIDDLEWARE_ENABLED=false
VALIDATION_STRICT=false
SANITIZE_OUTPUT=false
ALLOWED_ROOTS=[]
MAX_PATH_DEPTH=10
MAX_PARAM_LENGTH=10000
DANGEROUS_PATTERNS=[
"[;&|`$(){}\\[\\]<>]",
"\\.\\.[/\\\\]",
"[\\x00-\\x1f\\x7f-\\x9f]"
]

🎯 Security Impact


Prevents:

  • Directory traversal
  • Shell/command injection
  • SQL injection attempts
  • XSS injection into tool metadata
  • Malicious binary/control-character output

Benefits:

  • Stronger baseline security posture
  • Consistent validation across the entire gateway
  • Clean and predictable output guarantees
    -Foundation for future MCP spec hardening

🛡️ Quick Security Validation Tests

Essential attack patterns that MUST be blocked by the Gateway.


Export environment variables for each mode and check logs.

This section explains—step by step—how to run the gateway in different validation modes and verify the expected log behavior.

Validation Behavior Summary

This document explains how validation behaves based on different environment configurations.

🧪 Development Mode — Validation Disabled

Environment variables:

export ENVIRONMENT=development

export VALIDATION_MIDDLEWARE_ENABLED=true
export EXPERIMENTAL_VALIDATE_IO=false
export VALIDATION_STRICT=false
export SANITIZE_OUTPUT=false
make serve

Behavior:

  • Validation is disabled.
  • No warning logs appear.
  • Useful when rapidly iterating during development.

🧪 Development Mode — Validation Enabled

Environment variables:

export ENVIRONMENT=development

export VALIDATION_MIDDLEWARE_ENABLED=true
export EXPERIMENTAL_VALIDATE_IO=true
export VALIDATION_STRICT=true
export SANITIZE_OUTPUT=true
make serve

Behavior:

  • Validation runs, but environment is non-production.
  • System logs warnings, not errors.
  • Helps developers identify issues without blocking execution.

Example log level:

WARNING – validation warnings appear in logs

🚀 Production Mode — Validation Enabled

Environment variables:

export ENVIRONMENT=production

export VALIDATION_MIDDLEWARE_ENABLED=true
export EXPERIMENTAL_VALIDATE_IO=true
export VALIDATION_STRICT=true
export SANITIZE_OUTPUT=true
make serve

Behavior:

  • Full input/output validation is enabled.
  • Failures trigger ERROR logs.
  • Strict enforcement to avoid invalid payloads reaching downstream systems.

Example log:

mcpgateway.middleware.validation_middleware - ERROR - [VALIDATION] Input validation failed

🧪 Test Script

#!/bin/bash
# Quick security validation tests - Essential attacks that MUST be blocked

BASE_URL="http://localhost:4444"
TOKEN="Paste token here"


#########################################
# LOGGING HELPERS
#########################################

log_info()    { echo -e "\033[34mℹ️  INFO:\033[0m $1"; }
log_warn()    { echo -e "\033[33m⚠️  WARNING:\033[0m $1"; }
log_error()   { echo -e "\033[31m❌ ERROR:\033[0m $1"; }
log_ok()      { echo -e "\033[32m✔️  OK:\033[0m $1"; }

#########################################
# RESPONSE HELPERS
#########################################

extract_status() {
    echo "$1" | sed -n 's/.*HTTPSTATUS://p'
}

extract_body() {
    echo "$1" | sed 's/HTTPSTATUS:.*//'
}

call_api() {
    curl -s -w "HTTPSTATUS:%{http_code}" "$@"
}

check_result() {
    body="$1"

    # If any error/warning message appears → blocked correctly
    if echo "$body" | grep -Ei "error|value error|validation|failed|cannot|not allowed|invalid|html tags|directory traversal|metacharacters"; then
        log_ok "Attack BLOCKED as expected"
        return
    fi

    # Successful unsafe acceptance = BAD
    log_error "Should have been BLOCKED"
}


check_allowed() {
    if echo "$1" | grep -q "\"id\""; then
        log_ok "Allowed as expected"
    else
        log_error "Should have been ALLOWED"
    fi
}

#########################################
# START TESTING
#########################################

log_info "Starting Quick Security Tests"
echo "==================================="

#########################################
echo "🔒 Test 1: Path Traversal"
resp=$(call_api -X POST "$BASE_URL/resources" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "resource": {
      "uri": "../../../etc/passwd",
      "name": "test_traversal",
      "content": "dummy"
    },
    "team_id": null,
    "visibility": "private"
  }')

body=$(extract_body "$resp")
status=$(extract_status "$resp")

echo "$body" | jq .
log_info "HTTP Status: $status"
check_result "$body"
echo ""

#########################################
echo "🔒 Test 2: Shell Injection"
resp=$(call_api -X POST "$BASE_URL/tools" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tool": {"name": "test_shell", "description": "ls && cat /etc/passwd"}}')

body=$(extract_body "$resp")
status=$(extract_status "$resp")

echo "$body" | jq .
log_info "HTTP Status: $status"
check_result "$body"
echo ""

#########################################
echo "🔒 Test 3: SQL Injection"
resp=$(call_api -X POST "$BASE_URL/tools" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tool": {"name": "test_sql", "description": "'"'"'; DROP TABLE users; --"}}')

body=$(extract_body "$resp")
status=$(extract_status "$resp")

echo "$body" | jq .
log_info "HTTP Status: $status"
check_result "$body"
echo ""

#########################################
echo "🔒 Test 4: XSS"
resp=$(call_api -X POST "$BASE_URL/tools" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tool": {"name": "test_xss", "description": "<script>alert(1)</script>"}}')

body=$(extract_body "$resp")
status=$(extract_status "$resp")

echo "$body" | jq .
log_info "HTTP Status: $status"
check_result "$body"
echo ""

#########################################
echo "🔒 Test 5: Dangerous URL"
resp=$(call_api -X POST "$BASE_URL/tools" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tool": {"name": "test_url", "url": "javascript:alert(1)"}}')

body=$(extract_body "$resp")
status=$(extract_status "$resp")

echo "$body" | jq .
log_info "HTTP Status: $status"
check_result "$body"
echo ""

#########################################
echo "✅ Test 6: Safe Command"
resp=$(call_api -X POST "$BASE_URL/tools" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"tool\": {\"name\": \"safe_tool_$(date +%s)\", \"description\": \"echo hello world\"}}")

body=$(extract_body "$resp")
status=$(extract_status "$resp")

echo "$body" | jq .
log_info "HTTP Status: $status"
check_allowed "$body"
echo ""

log_info "🏁 All tests completed!"

@nmveeresh nmveeresh marked this pull request as ready for review December 2, 2025 10:18
@rakdutta rakdutta self-requested a review December 8, 2025 09:06
Copy link
Copy Markdown
Collaborator

@rakdutta rakdutta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is working as expected. When testing through the main API, we correctly receive a warning message in the development environment and an error message in the production environment.
However, in the Admin UI, the user should also receive a clear and user-friendly warning or error message.

Please create a separate PR to address this UI handling issue.

nmveeresh and others added 6 commits December 12, 2025 17:27
Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>
Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>
Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>
Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>
Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai force-pushed the feature/security-gateway-io-validation-221 branch from aec5026 to d28a828 Compare December 12, 2025 17:45
@crivetimihai crivetimihai merged commit f2183b1 into main Dec 12, 2025
52 checks passed
@crivetimihai crivetimihai deleted the feature/security-gateway-io-validation-221 branch December 12, 2025 17:52
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
…BM#1536)

* added input security validation

Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>

* testcases fixed

Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>

* fixed config.py

Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>

* added env vars and fixed validation code

Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>

* remove input_validator.py file

Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>

* fix: remove duplicate SecurityValidator import

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Veeresh K <veeruveeresh1522@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE][SECURITY]: Gateway-level input validation and output sanitization

3 participants