Input Validation & Output Sanitization¶
Overview¶
ContextForge provides comprehensive input validation and output sanitization to protect against common security vulnerabilities including:
- Path Traversal: Prevents access to files outside allowed directories
- Command Injection: Blocks shell metacharacters in parameters
- SQL Injection: Validates and escapes SQL parameters
- XSS Attacks: Sanitizes output to remove dangerous content
- Control Character Injection: Removes ANSI escape sequences and control characters
Configuration¶
Environment Variables¶
# Enable experimental validation (default: false)
EXPERIMENTAL_VALIDATE_IO=true
# Enable validation middleware (default: false)
VALIDATION_MIDDLEWARE_ENABLED=true
# Strict mode - reject on violations (default: true)
VALIDATION_STRICT=true
# Sanitize output responses (default: true)
SANITIZE_OUTPUT=true
# Allowed root paths for resource access (JSON array or comma-separated)
ALLOWED_ROOTS='["/srv/data", "/var/app"]'
# Maximum path depth (default: 10)
MAX_PATH_DEPTH=10
# Maximum parameter length (default: 10000)
MAX_PARAM_LENGTH=10000
# Dangerous patterns (regex, JSON array)
DANGEROUS_PATTERNS='["[;&|`$(){}\\[\\]<>]", "\\.\\.[\\\/]", "[\\x00-\\x1f\\x7f-\\x9f]"]'
Roll-out Phases¶
The validation feature supports a phased roll-out approach:
Phase 0: Feature Flag (Off by Default)¶
Phase 1: Log-Only Mode (Dev/Staging)¶
Phase 2: Enforce in Staging¶
Phase 3: Production Deployment¶
Validation Rules¶
Path Traversal Defense¶
Scenario: Reject resource path traversal
# Configuration
MCP_GW_ROOT="/srv/data"
# Attack attempt
uri = "/srv/data/../../secret.txt"
# Result: 400 "invalid_path: Path traversal detected"
# No files outside "/srv/data" are accessed
Implementation:
- Normalizes paths using
Path.resolve() - Checks for
..sequences - Validates against
ALLOWED_ROOTS - Enforces
MAX_PATH_DEPTHlimit
Command Injection Prevention¶
Scenario: Prevent command injection via filename
# Tool that shells out with filename parameter
filename = "bobbytables.jpg; cat /etc/passwd"
# Strict mode: Rejects with 422 "validation_failed"
# Non-strict mode: Escapes value using shlex.quote()
Protected Patterns:
- Shell metacharacters:
; & | \$ ( ) { } [ ] < >` - Command chaining:
&&,||,; - Pipe operators:
| - Backticks and command substitution
SQL Injection Prevention¶
Scenario: Validate SQL parameters
# Dangerous input
param = "'; DROP TABLE users; --"
# Strict mode: Rejects with 422 "validation_failed"
# Non-strict mode: Escapes quotes
Protected Patterns:
- Quote characters:
'," - SQL comments:
--,/* */ - SQL keywords:
UNION,SELECT,INSERT,UPDATE,DELETE,DROP
Output Sanitization¶
Scenario: Sanitize tool output
# Tool returns text with control characters
output = "Result: \x1b[31mError\x1b[0m\x00"
# Sanitized output
clean = "Result: Error"
# Control chars removed, Content-Type verified
Sanitization Rules:
- Removes C0 control characters (0x00-0x1F) except newlines/tabs
- Removes ANSI escape sequences
- Removes C1 control characters (0x7F-0x9F)
- Preserves
\n(newline) and\t(tab) - Verifies Content-Type matches payload
Tool Description Content Validation¶
Scenario: MCP server tools whose descriptions contain Markdown syntax fail to register
Blocked patterns: >, <, &&, ||, $(
These shell metacharacters are blocked by default in ToolCreate and ToolUpdate to reduce injection risk from externally-sourced tool metadata. However, they are common in Markdown content (e.g. > blockquote, < input). Note: single pipes (|), semicolons (;), and backticks (`) are explicitly allowed as they commonly appear in natural-language documentation and Markdown tables.
Control variables:
| Variable | Default | Effect |
|---|---|---|
TOOL_DESCRIPTION_FORBIDDEN_PATTERNS_ENABLED | true | Master switch — set to false to disable all pattern checks |
TOOL_DESCRIPTION_FORBIDDEN_PATTERNS | ["&&", "||", "$(", "> ", "< "] | Override the blocked substrings (JSON array) |
VALIDATION_STRICT | true | When false, matched patterns log a warning instead of rejecting |
Option 1 — Customize the pattern list (recommended):
# Keep injection checks but allow pipe and redirect syntax in descriptions
TOOL_DESCRIPTION_FORBIDDEN_PATTERNS=["&&", "||", "$("]
Option 2 — Disable pattern checks entirely:
Option 3 — Warn-only mode (all patterns checked but never rejected):
When VALIDATION_STRICT=false: - The forbidden-pattern check in ToolCreate.validate_description and ToolUpdate.validate_description logs a warning and proceeds instead of raising a validation error. - All other sanitization (XSS, length truncation) still runs.
Upgrade note (v0.9.0 → v1.0.0.Beta2)
The forbidden-pattern check was introduced in v1.0.0.Beta2. If you are upgrading from v0.9.0 and your MCP servers expose tools with Markdown descriptions, set VALIDATION_STRICT=false or customize TOOL_DESCRIPTION_FORBIDDEN_PATTERNS to allow the specific characters your tools use.
JSON Schema Validation¶
Scenario: Validate tool and prompt schemas during registration
# Tool registration with invalid schema
tool = {
"name": "invalid_tool",
"inputSchema": {
"type": "object",
"properties": {"arg": {"type": "unknown_type"}} # Invalid type
}
}
# Strict mode (Default): Rejects with 400 Bad Request
# Non-strict mode: Logs warning but accepts registration
Control variable: JSON_SCHEMA_VALIDATION_STRICT (default: true)
Validation Rules: - Enforces valid JSON Schema 2020-12 (default) - Validates structural integrity of inputSchema for tools - Validates arguments schema for tool prompts - prevents registration of broken tools that would fail at runtime
API Usage¶
SecurityValidator Class¶
from mcpgateway.common.validators import SecurityValidator
# Validate shell parameters
safe_param = SecurityValidator.validate_shell_parameter("filename.txt")
# Validate paths
safe_path = SecurityValidator.validate_path("/srv/data/file.txt", ["/srv/data"])
# Validate SQL parameters
safe_sql = SecurityValidator.validate_sql_parameter("user_input")
# Sanitize output
clean_text = SecurityValidator.sanitize_text("Text\x1b[31mwith\x1b[0mcolors")
# Sanitize JSON responses
clean_data = SecurityValidator.sanitize_json_response({
"message": "Hello\x1bWorld",
"items": ["test\x00", "clean"]
})
ValidationMiddleware¶
The middleware automatically validates all incoming requests when enabled:
# In main.py
from mcpgateway.middleware.validation_middleware import ValidationMiddleware
if settings.validation_middleware_enabled:
app.add_middleware(ValidationMiddleware)
Testing¶
Unit Tests¶
import pytest
from mcpgateway.common.validators import SecurityValidator
def test_path_traversal_blocked():
"""Test path traversal is blocked."""
with pytest.raises(ValueError, match="Path traversal"):
SecurityValidator.validate_path("../../../etc/passwd")
def test_command_injection_blocked():
"""Test command injection is blocked."""
with pytest.raises(ValueError, match="shell metacharacters"):
SecurityValidator.validate_shell_parameter("file; rm -rf /")
def test_output_sanitization():
"""Test output sanitization removes control chars."""
result = SecurityValidator.sanitize_text("Hello\x1b[31mWorld\x00")
assert result == "HelloWorld"
Integration Tests¶
# Test path traversal protection
curl -X POST http://localhost:4444/resources \
-H "Authorization: Bearer $TOKEN" \
-d '{"uri": "../../../etc/passwd"}'
# Expected: 400 Bad Request
# Test command injection protection
curl -X POST http://localhost:4444/tools/call \
-H "Authorization: Bearer $TOKEN" \
-d '{"name": "convert", "arguments": {"file": "test; cat /etc/passwd"}}'
# Expected: 422 Validation Failed (strict mode)
Metrics & Monitoring¶
Log Messages¶
[VALIDATION] Input validation failed: Parameter contains shell metacharacters
[VALIDATION] Path traversal detected: ../../../etc/passwd
[SECURITY] Path validation failed: Path outside allowed roots
Prometheus Metrics¶
# Validation failures
mcpgateway_validation_failures_total{type="path_traversal"} 5
mcpgateway_validation_failures_total{type="command_injection"} 2
mcpgateway_validation_failures_total{type="sql_injection"} 1
# Sanitization operations
mcpgateway_sanitization_operations_total{type="output"} 1234
Security Best Practices¶
1. Enable Validation in Production¶
Always enable validation in production environments:
2. Configure Allowed Roots¶
Restrict resource access to specific directories:
3. Use Strict Mode¶
Enable strict mode to reject invalid input:
4. Monitor Validation Failures¶
Set up alerts for validation failures:
# Prometheus alert
- alert: HighValidationFailureRate
expr: rate(mcpgateway_validation_failures_total[5m]) > 10
annotations:
summary: "High rate of validation failures detected"
5. Regular Security Audits¶
Review validation logs regularly:
# Check for validation failures
grep "VALIDATION" /var/log/mcpgateway.log | tail -100
# Check for security warnings
grep "SECURITY" /var/log/mcpgateway.log | tail -100
Troubleshooting¶
Issue: Legitimate Paths Blocked¶
Symptom: Valid file paths are rejected
Solution: Add path to ALLOWED_ROOTS:
Issue: MCP Server Tools Fail to Register with "unsafe characters" Error¶
Symptom:
All N tools failed validation. First error: Validation failed for tool 'X':
[{'type': 'value_error', 'loc': ('description',),
'msg': "Value error, Description contains unsafe characters: '> '", ...}]
Cause: The tool's description field contains a shell metacharacter (>, <, &&, ||, $() that is blocked by default. This is common with Markdown-formatted descriptions. Note: single pipes (|), semicolons (;), and backticks (`) are allowed as they commonly appear in natural-language documentation.
Solution (pick one):
# Option 1: Customize the pattern list to allow specific characters
TOOL_DESCRIPTION_FORBIDDEN_PATTERNS=["&&", "||", "$("]
# Option 2: Disable pattern checks entirely
TOOL_DESCRIPTION_FORBIDDEN_PATTERNS_ENABLED=false
# Option 3: Warn-only mode (log but don't reject)
VALIDATION_STRICT=false
Note: EXPERIMENTAL_VALIDATE_IO=false and JSON_SCHEMA_VALIDATION_STRICT=false do not affect this check — only VALIDATION_STRICT and TOOL_DESCRIPTION_FORBIDDEN_PATTERNS_ENABLED do.
Issue: Tool Parameters Escaped¶
Symptom: Tool receives escaped parameters
Solution: Disable strict mode for specific tools or use non-strict mode:
Issue: Output Appears Corrupted¶
Symptom: Output missing formatting
Solution: Control characters were sanitized. This is expected behavior for security.
Upstream Spec Proposal¶
Validation Clause¶
Servers MUST treat all inbound values as untrusted and validate them against JSON Schema or allow-lists.
Path-Safety Clause¶
Resource paths MUST resolve inside configured roots; otherwise reject with 400 status.
Dangerous-Sink Clause¶
Parameters passed to shells/SQL MUST be escaped or rejected to prevent injection attacks.
Output-Sanitization Clause¶
Before emission, servers SHOULD strip control chars and MUST ensure MIME correctness.