From 4dce9800a5c39d70585455ff414a2f2ea0a97f32 Mon Sep 17 00:00:00 2001 From: Molecule AI Fullstack Engineer Date: Tue, 12 May 2026 06:30:25 +0000 Subject: [PATCH] =?UTF-8?q?fix(handlers):=20OFFSEC-001=20=E2=80=94=20scrub?= =?UTF-8?q?=20req.Method=20from=20dispatchRPC=20default=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Line 443 of mcp.go concatenated user-controlled req.Method into the JSON-RPC -32601 error message, allowing an agent or canvas client to inject arbitrary strings into the response via the method field. Fix: replace "method not found: " + req.Method with the constant "method not found" — matching the OFFSEC-001 scrub contract applied to the InvalidParams (line 428) and UnknownTool (line 433) paths. Test: extend TestMCPHandler_UnknownMethod_Returns32601 with two new assertions: 1. resp.Error.Message == "method not found" 2. defence-in-depth check that the sent method name never appears in the response (strings.Contains guard) Issue: #684 Co-Authored-By: Claude Opus 4.7 --- workspace-server/internal/handlers/mcp.go | 3 ++- workspace-server/internal/handlers/mcp_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/workspace-server/internal/handlers/mcp.go b/workspace-server/internal/handlers/mcp.go index 3065ca4a..707c12f2 100644 --- a/workspace-server/internal/handlers/mcp.go +++ b/workspace-server/internal/handlers/mcp.go @@ -434,7 +434,8 @@ func (h *MCPHandler) dispatchRPC(ctx context.Context, workspaceID string, req mc } default: - base.Error = &mcpRPCError{Code: -32601, Message: "method not found: " + req.Method} + // Per OFFSEC-001: error message must not include user-controlled req.Method. + base.Error = &mcpRPCError{Code: -32601, Message: "method not found"} } return base diff --git a/workspace-server/internal/handlers/mcp_test.go b/workspace-server/internal/handlers/mcp_test.go index dbad430a..d306fa14 100644 --- a/workspace-server/internal/handlers/mcp_test.go +++ b/workspace-server/internal/handlers/mcp_test.go @@ -9,6 +9,7 @@ import ( "net/http" "net/http/httptest" "os" + "strings" "testing" "errors" @@ -204,6 +205,9 @@ func TestMCPHandler_NotificationsInitialized_Returns200(t *testing.T) { // Unknown method // ───────────────────────────────────────────────────────────────────────────── +// TestMCPHandler_UnknownMethod_Returns32601 verifies dispatchRPC returns +// -32601 for an unknown method. Per OFFSEC-001: the error message must be +// constant — req.Method is user-controlled and must NOT appear in the response. func TestMCPHandler_UnknownMethod_Returns32601(t *testing.T) { h, _ := newMCPHandler(t) @@ -224,6 +228,14 @@ func TestMCPHandler_UnknownMethod_Returns32601(t *testing.T) { if resp.Error.Code != -32601 { t.Errorf("expected code -32601, got %d", resp.Error.Code) } + // Message must be constant — no user-controlled method name leak. + if resp.Error.Message != "method not found" { + t.Errorf("error message should be constant 'method not found', got: %q", resp.Error.Message) + } + // Double-check the method name never appears in the message (defence-in-depth). + if strings.Contains(resp.Error.Message, "not/a/real/method") { + t.Error("error message must not echo the user-controlled method name") + } } // ─────────────────────────────────────────────────────────────────────────────