-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Expand file tree
/
Copy pathtest_malformed_input.py
More file actions
139 lines (119 loc) · 5.67 KB
/
test_malformed_input.py
File metadata and controls
139 lines (119 loc) · 5.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Claude Debug
"""Test for HackerOne vulnerability report #3156202 - malformed input DOS."""
import anyio
import pytest
from mcp.server.models import InitializationOptions
from mcp.server.session import ServerSession
from mcp.shared.message import SessionMessage
from mcp.types import INVALID_PARAMS, JSONRPCError, JSONRPCMessage, JSONRPCRequest, ServerCapabilities
@pytest.mark.anyio
async def test_malformed_initialize_request_does_not_crash_server():
"""Test that malformed initialize requests return proper error responses
instead of crashing the server (HackerOne #3156202).
"""
# Create in-memory streams for testing
read_send_stream, read_receive_stream = anyio.create_memory_object_stream[SessionMessage | Exception](10)
write_send_stream, write_receive_stream = anyio.create_memory_object_stream[SessionMessage](10)
try:
# Create a malformed initialize request (missing required params field)
malformed_request = JSONRPCRequest(
jsonrpc="2.0",
id="f20fe86132ed4cd197f89a7134de5685",
method="initialize",
# params=None # Missing required params field
)
# Wrap in session message
request_message = SessionMessage(message=malformed_request)
# Start a server session
async with ServerSession(
read_stream=read_receive_stream,
write_stream=write_send_stream,
init_options=InitializationOptions(
server_name="test_server",
server_version="1.0.0",
capabilities=ServerCapabilities(),
),
):
# Send the malformed request
await read_send_stream.send(request_message)
# Wait for the error response
with anyio.fail_after(5):
response_message = await write_receive_stream.receive()
response = response_message.message
# Verify it's a proper JSON-RPC error response
assert isinstance(response, JSONRPCError)
assert response.jsonrpc == "2.0"
assert response.id == "f20fe86132ed4cd197f89a7134de5685"
assert response.error.code == INVALID_PARAMS
assert "Invalid request parameters" in response.error.message
# Verify the session is still alive and can handle more requests
# Send another malformed request to confirm server stability
another_malformed_request = JSONRPCRequest(
jsonrpc="2.0",
id="test_id_2",
method="tools/call",
# params=None # Missing required params
)
another_request_message = SessionMessage(message=another_malformed_request)
await read_send_stream.send(another_request_message)
# Wait for the second error response
with anyio.fail_after(5):
second_response_message = await write_receive_stream.receive()
second_response = second_response_message.message
assert isinstance(second_response, JSONRPCError)
assert second_response.id == "test_id_2"
assert second_response.error.code == INVALID_PARAMS
finally: # pragma: lax no cover
# Close all streams to ensure proper cleanup
await read_send_stream.aclose()
await write_send_stream.aclose()
await read_receive_stream.aclose()
await write_receive_stream.aclose()
@pytest.mark.anyio
async def test_multiple_concurrent_malformed_requests():
"""Test that multiple concurrent malformed requests don't crash the server."""
# Create in-memory streams for testing
read_send_stream, read_receive_stream = anyio.create_memory_object_stream[SessionMessage | Exception](100)
write_send_stream, write_receive_stream = anyio.create_memory_object_stream[SessionMessage](100)
try:
# Start a server session
async with ServerSession(
read_stream=read_receive_stream,
write_stream=write_send_stream,
init_options=InitializationOptions(
server_name="test_server",
server_version="1.0.0",
capabilities=ServerCapabilities(),
),
):
# Send multiple malformed requests concurrently
malformed_requests: list[SessionMessage] = []
for i in range(10):
malformed_request = JSONRPCRequest(
jsonrpc="2.0",
id=f"malformed_{i}",
method="initialize",
# params=None # Missing required params
)
request_message = SessionMessage(message=malformed_request)
malformed_requests.append(request_message)
# Send all requests
for request in malformed_requests:
await read_send_stream.send(request)
# Collect all 10 error responses
error_responses: list[JSONRPCMessage] = []
with anyio.fail_after(5):
for _ in range(10):
response_message = await write_receive_stream.receive()
error_responses.append(response_message.message)
assert len(error_responses) == 10
for i, response in enumerate(error_responses):
assert isinstance(response, JSONRPCError)
assert response.id == f"malformed_{i}"
assert response.error.code == INVALID_PARAMS
finally: # pragma: lax no cover
# Close all streams to ensure proper cleanup
await read_send_stream.aclose()
await write_send_stream.aclose()
await read_receive_stream.aclose()
await write_receive_stream.aclose()