Skip to content

Commit 7a31a25

Browse files
authored
Validate inputs to admin and main APIs (#347)
* Use safe create classes and update test cases Signed-off-by: Madhav Kandukuri <[email protected]> * Linting fixes Signed-off-by: Madhav Kandukuri <[email protected]> * Minor linting fix Signed-off-by: Madhav Kandukuri <[email protected]> * Add secure update classes Signed-off-by: Madhav Kandukuri <[email protected]> * Remove Secure from class names Signed-off-by: Madhav Kandukuri <[email protected]> * Update uv.lock Signed-off-by: Madhav Kandukuri <[email protected]> * Add tests for validator Signed-off-by: Madhav Kandukuri <[email protected]> * Linting fixes Signed-off-by: Madhav Kandukuri <[email protected]> * Fix REST tool addition Signed-off-by: Madhav Kandukuri <[email protected]>
1 parent baf0797 commit 7a31a25

File tree

10 files changed

+1447
-151
lines changed

10 files changed

+1447
-151
lines changed

mcpgateway/config.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,46 @@ def validate_database(self) -> None:
291291
if not db_dir.exists():
292292
db_dir.mkdir(parents=True)
293293

294+
# Validation patterns for safe display (configurable)
295+
validation_dangerous_html_pattern: str = r"<(script|iframe|object|embed|link|meta|base|form)\b|</*(script|iframe|object|embed|link|meta|base|form)>"
296+
validation_dangerous_js_pattern: str = r"javascript:|vbscript:|on\w+\s*=|data:.*script"
297+
validation_allowed_url_schemes: List[str] = ["http://", "https://", "ws://", "wss://"]
298+
299+
# Character validation patterns
300+
validation_name_pattern: str = r"^[a-zA-Z0-9_\-\s]+$" # Allow spaces for names
301+
validation_identifier_pattern: str = r"^[a-zA-Z0-9_\-\.]+$" # No spaces for IDs
302+
validation_safe_uri_pattern: str = r"^[a-zA-Z0-9_\-.:/?=&%]+$"
303+
validation_unsafe_uri_pattern: str = r'[<>"\'\\]'
304+
validation_tool_name_pattern: str = r"^[a-zA-Z][a-zA-Z0-9_-]*$" # MCP tool naming
305+
306+
# MCP-compliant size limits (configurable via env)
307+
validation_max_name_length: int = 255
308+
validation_max_description_length: int = 4096
309+
validation_max_template_length: int = 65536 # 64KB
310+
validation_max_content_length: int = 1048576 # 1MB
311+
validation_max_json_depth: int = 10
312+
validation_max_url_length: int = 2048
313+
validation_max_rpc_param_size: int = 262144 # 256KB
314+
315+
# Allowed MIME types
316+
validation_allowed_mime_types: List[str] = [
317+
"text/plain",
318+
"text/html",
319+
"text/css",
320+
"text/javascript",
321+
"application/json",
322+
"application/xml",
323+
"application/pdf",
324+
"image/png",
325+
"image/jpeg",
326+
"image/gif",
327+
"image/svg+xml",
328+
"application/octet-stream",
329+
]
330+
331+
# Rate limiting
332+
validation_max_requests_per_minute: int = 60
333+
294334

295335
def extract_using_jq(data, jq_filter=""):
296336
"""

mcpgateway/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,8 @@ class Root(BaseModel):
532532
name (Optional[str]): An optional human-readable name.
533533
"""
534534

535+
model_config = ConfigDict(arbitrary_types_allowed=True)
536+
535537
uri: Union[FileUrl, AnyUrl] = Field(..., description="Unique identifier for the root")
536538
name: Optional[str] = Field(None, description="Optional human-readable name")
537539

0 commit comments

Comments
 (0)