fix(handlers): OFFSEC-001 — scrub req.Method from dispatchRPC default error
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 <noreply@anthropic.com>
This commit is contained in:
parent
965710eb00
commit
b1d6c4476a
@ -440,7 +440,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
|
||||
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Loading…
Reference in New Issue
Block a user