MCPcopy Create free account
hub / github.com/modelcontextprotocol/go-sdk / TestSessionHijackingPrevention

Function TestSessionHijackingPrevention

mcp/streamable_test.go:1754–1828  ·  view source on GitHub ↗
(t *testing.T)

Source from the content-addressed store, hash-verified

1752}
1753
1754func TestSessionHijackingPrevention(t *testing.T) {
1755 // This test verifies that sessions bound to a user ID cannot be accessed
1756 // by a different user (session hijacking prevention).
1757 ctx := context.Background()
1758
1759 server := NewServer(testImpl, nil)
1760 streamHandler := NewStreamableHTTPHandler(func(req *http.Request) *Server { return server }, nil)
1761
1762 // Use the bearer token directly as the user ID. This simulates how a real
1763 // verifier might extract a user ID from a JWT "sub" claim or introspection.
1764 verifier := func(_ context.Context, token string, _ *http.Request) (*auth.TokenInfo, error) {
1765 return &auth.TokenInfo{
1766 Scopes: []string{"scope"},
1767 UserID: token,
1768 Expiration: time.Date(5000, 1, 2, 3, 4, 5, 0, time.UTC),
1769 }, nil
1770 }
1771 handler := auth.RequireBearerToken(verifier, nil)(streamHandler)
1772 httpServer := httptest.NewServer(mustNotPanic(t, handler))
1773 defer httpServer.Close()
1774
1775 // Helper to send a JSON-RPC request as a given user.
1776 doRequest := func(msg jsonrpc.Message, sessionID, userID string) *http.Response {
1777 t.Helper()
1778 data, _ := jsonrpc2.EncodeMessage(msg)
1779 req, _ := http.NewRequestWithContext(ctx, http.MethodPost, httpServer.URL, bytes.NewReader(data))
1780 req.Header.Set("Content-Type", "application/json")
1781 req.Header.Set("Accept", "application/json, text/event-stream")
1782 req.Header.Set("Authorization", "Bearer "+userID)
1783 if sessionID != "" {
1784 req.Header.Set(sessionIDHeader, sessionID)
1785 }
1786 resp, err := http.DefaultClient.Do(req)
1787 if err != nil {
1788 t.Fatalf("request failed: %v", err)
1789 }
1790 return resp
1791 }
1792
1793 // Create a session as user1.
1794 initReq := &jsonrpc.Request{Method: "initialize", ID: jsonrpc2.Int64ID(1)}
1795 initReq.Params, _ = json.Marshal(&InitializeParams{
1796 ProtocolVersion: protocolVersion20250618,
1797 ClientInfo: &Implementation{Name: "test", Version: "1.0"},
1798 })
1799 resp := doRequest(initReq, "", "user1")
1800 defer resp.Body.Close()
1801 if resp.StatusCode != http.StatusOK {
1802 body, _ := io.ReadAll(resp.Body)
1803 t.Fatalf("initialize failed with status %d: %s", resp.StatusCode, body)
1804 }
1805 sessionID := resp.Header.Get(sessionIDHeader)
1806 if sessionID == "" {
1807 t.Fatal("no session ID in response")
1808 }
1809
1810 pingReq := &jsonrpc.Request{Method: "ping", ID: jsonrpc2.Int64ID(2)}
1811 pingReq.Params, _ = json.Marshal(&PingParams{})

Callers

nothing calls this directly

Calls 7

RequireBearerTokenFunction · 0.92
EncodeMessageFunction · 0.92
Int64IDFunction · 0.92
NewServerFunction · 0.85
NewStreamableHTTPHandlerFunction · 0.85
mustNotPanicFunction · 0.85
CloseMethod · 0.65

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…