Fix access violation on unparseable JSON-RPC requests - #17
Merged
cmgeuze merged 1 commit intoJul 14, 2026
Merged
Conversation
When TJSONObject.ParseJSONValue rejects a request body, ParseJSONRequest
raises before JSONRequest is assigned, and the except handler in
ProcessRequest then called ExtractRequestID(nil). The nil dereference
surfaces as "Access violation ... Read of address 0000000000000010"
(TJSONObject.GetValue on a nil instance) for any syntactically invalid
request - a stray BOM, a truncated line, or hand-built JSON containing
raw Windows paths (in "C:\ProgramData\..." the \P is an invalid escape).
In servers that embed a database engine the escaped AV is even worse
than the failed request: it can trip process-wide fatal-error handling.
- ExtractRequestID: return TValue.Empty for a nil request object
- ProcessRequest: report JSONRPC_PARSE_ERROR (-32700) per JSON-RPC 2.0
when the body never parsed, instead of -32603
- StdioTransport: build the transport-level error response with
TJSONObject instead of string concatenation that only escaped quotes,
which emitted invalid JSON whenever the exception message contained a
backslash or control character
Verified on Win64 (stdio transport): before, invalid escapes and plain
garbage each produced the access violation; after, both return
{"code":-32700,"message":"Invalid JSON"} and the server keeps serving.
Correctly escaped backslashes in arguments were unaffected before and
after.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
|
Verified locally on Win64: reproduced the access violation on |
Member
|
Hi @eivindbakkestuen, your fix from this PR is still in and now has tests around it. The 2026-07-28 MCP revision is on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Any request whose body fails JSON parsing crashes the server with an access violation instead of returning a JSON-RPC error:
Easy ways to trigger it:
this is not json {{{"C:\ProgramData\Oops"the\Pis an invalid JSON escapeCorrectly escaped arguments (e.g.
"C:\\ProgramData\\Data") were never affected — this only concerns bodies thatTJSONObject.ParseJSONValuerejects.Root cause
In
TMCPJsonRpcProcessor.ProcessRequest,ParseJSONRequestraises beforeJSONRequestis assigned, and theexcepthandler then callsExtractRequestID(JSONRequest)withJSONRequest = nil.TJSONObject.GetValueon a nil instance reads offset$10— confirmed by symbolicating the AV address against a detailed map file.The transport loop catches the escaped AV so the demo server survives, but hosts that embed more machinery can fare much worse: we found this in a NexusDB-based MCP server where the embedded database engine's process-wide exception hook treats any access violation as fatal and suspends all database operations until the process is restarted. A malformed request should never cost more than an error response.
Fix
ExtractRequestID: returnTValue.Emptywhen the request object is nil.ProcessRequest: reportJSONRPC_PARSE_ERROR(-32700, per JSON-RPC 2.0) instead of -32603 when the body never parsed.TMCPStdioTransport.Run: build the transport-level error response withTJSONObjectinstead of string concatenation that only escaped quotes — the old code emitted invalid JSON whenever the exception message contained a backslash (e.g. a Windows path) or a control character.Verification
Win64, stdio transport, both builds from this same base revision (419b512):
{"...,"message":"C:\ProgramData\Oops"}(invalid escape)Access violation ... Read of address 0000000000000010{"code":-32700,"message":"Invalid JSON"}this is not json {{{{"code":-32700,"message":"Invalid JSON"}{"...,"message":"C:\\ProgramData\\OZZIE\\Data"}(valid)🤖 Generated with Claude Code