diff --git a/.yarnrc.yml b/.yarnrc.yml index 6cda6547f0..d1f47a1dc7 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -13,3 +13,7 @@ npmPreapprovedPackages: # npmMinimalAgeGate window. - 'nx' - '@nx/*' + # TODO: remove once undici@7.30.2 (published 2026-11-05) is older than the + # npmMinimalAgeGate window. 7.30.2 is the security release fixing + # CVE-2026-116592, -120474, -120415, -120423, -120222 and -116630. + - 'undici' diff --git a/packages/api/package.json b/packages/api/package.json index e1ca44871e..c5c88665ad 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -25,7 +25,7 @@ "@hyperdx/common-utils": "^0.32.0", "@hyperdx/node-opentelemetry": "^0.9.0", "@hyperdx/passport-local-mongoose": "^9.0.1", - "@modelcontextprotocol/sdk": "^1.27.1", + "@modelcontextprotocol/sdk": "^1.32.2", "@opentelemetry/api": "^1.8.0", "@opentelemetry/host-metrics": "^0.35.5", "@opentelemetry/sdk-metrics": "^1.30.1", @@ -50,7 +50,7 @@ "lodash": "^4.18.1", "minimist": "^1.2.7", "mongodb": "^6.15.0", - "mongoose": "^6.13.10", + "mongoose": "^6.13.12", "ms": "^2.1.3", "on-headers": "^1.1.0", "passport": "^0.6.0", diff --git a/packages/api/src/mcp/__tests__/toolInputLimit.test.ts b/packages/api/src/mcp/__tests__/toolInputLimit.test.ts new file mode 100644 index 0000000000..c283508cd1 --- /dev/null +++ b/packages/api/src/mcp/__tests__/toolInputLimit.test.ts @@ -0,0 +1,32 @@ +import { MAX_TOOL_INPUT_ELEMENTS } from '@/mcp/mcpServer'; +import { McpContext } from '@/mcp/tools/types'; + +import { callTool, createTestClient, getFirstText } from './mcpTestUtils'; + +const context: McpContext = { teamId: 'team-id', userId: 'user-id' }; + +// GHSA-46jr-4wx8-v453 / CVE-2026-111768: without maxToolInputElements the SDK +// validates arbitrarily many array elements / object keys per tool call and +// can be driven into heap exhaustion. The element count is checked before the +// tool's schema runs, so any registered tool exercises it. +describe('MCP tool input element limit', () => { + it('bounds the limit well above any model-generated tool input', () => { + expect(MAX_TOOL_INPUT_ELEMENTS).toBeGreaterThanOrEqual(10_000); + expect(Number.isFinite(MAX_TOOL_INPUT_ELEMENTS)).toBe(true); + }); + + it('rejects a tool call whose arguments exceed the limit', async () => { + const client = await createTestClient(context); + const { tools } = await client.listTools(); + expect(tools.length).toBeGreaterThan(0); + + const result = await callTool(client, tools[0].name, { + padding: new Array(MAX_TOOL_INPUT_ELEMENTS + 1).fill(0), + }); + + expect(result.isError).toBe(true); + expect(getFirstText(result)).toContain( + `more than the maximum of ${MAX_TOOL_INPUT_ELEMENTS} elements`, + ); + }); +}); diff --git a/packages/api/src/mcp/mcpServer.ts b/packages/api/src/mcp/mcpServer.ts index 2411a704a7..603a5a8fc4 100644 --- a/packages/api/src/mcp/mcpServer.ts +++ b/packages/api/src/mcp/mcpServer.ts @@ -59,9 +59,16 @@ const SERVER_INFO: Implementation = { }), }; +// Upper bound on array elements + object members in one tools/call `arguments` +// payload (GHSA-46jr-4wx8-v453): the SDK leaves it unlimited by default, which +// lets one request exhaust the heap during validation. Model-generated tool +// input stays orders of magnitude below this. +export const MAX_TOOL_INPUT_ELEMENTS = 100_000; + export function createServer(context: McpContext) { const server = new McpServer(SERVER_INFO, { instructions: SERVER_INSTRUCTIONS, + maxToolInputElements: MAX_TOOL_INPUT_ELEMENTS, }); const registerTool = createRegisterTool(server, context); diff --git a/packages/otel-collector/go.mod b/packages/otel-collector/go.mod index f9efa9d17f..621b66c3a2 100644 --- a/packages/otel-collector/go.mod +++ b/packages/otel-collector/go.mod @@ -9,12 +9,12 @@ require ( require ( github.com/ClickHouse/ch-go v0.71.0 // indirect - github.com/andybalholm/brotli v1.2.0 // indirect + github.com/andybalholm/brotli v1.2.7 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.7.1 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.20.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/paulmach/orb v0.12.0 // indirect diff --git a/packages/otel-collector/go.sum b/packages/otel-collector/go.sum index fc4f8d1aaf..50d6c45e79 100644 --- a/packages/otel-collector/go.sum +++ b/packages/otel-collector/go.sum @@ -2,8 +2,8 @@ github.com/ClickHouse/ch-go v0.71.0 h1:bUdZ/EZj/LcVHsMqaRUP2holqygrPWQKeMjc6nZoy github.com/ClickHouse/ch-go v0.71.0/go.mod h1:NwbNc+7jaqfY58dmdDUbG4Jl22vThgx1cYjBw0vtgXw= github.com/ClickHouse/clickhouse-go/v2 v2.43.0 h1:fUR05TrF1GyvLDa/mAQjkx7KbgwdLRffs2n9O3WobtE= github.com/ClickHouse/clickhouse-go/v2 v2.43.0/go.mod h1:o6jf7JM/zveWC/PP277BLxjHy5KjnGX/jfljhM4s34g= -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.7 h1:UgafRPGMam5ySHfRkhthMqOFA6IFoeF3D7mWIDLjG5A= +github.com/andybalholm/brotli v1.2.7/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -28,8 +28,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.20.2 h1:v5tiZvm1KGLyg5d5oXdXe3lsSPrbEUiKoXGia//I7Qo= +github.com/klauspost/compress v1.20.2/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= diff --git a/yarn.lock b/yarn.lock index 1af4d01d09..4042ba20e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4662,12 +4662,12 @@ __metadata: languageName: node linkType: hard -"@hono/node-server@npm:^1.19.9": - version: 1.19.17 - resolution: "@hono/node-server@npm:1.19.17" +"@hono/node-server@npm:^1.19.9 || ^2.0.5": + version: 2.1.6 + resolution: "@hono/node-server@npm:2.1.6" peerDependencies: - hono: ^4 - checksum: 10c0/e77907e3b5db8ab68ed4f297ad84807bfdd698636408de86ab8d36dab4658504ac4c0ed9d9436bc272a0172b9b7a5a4b578532e0b5baf97674c7b420cb5cff4b + hono: ^4 || ^5.0.0-0 + checksum: 10c0/bb57a4e00f193b37f1e7c8a4b8206914ab3f6073d8e7da7ca4b005f0205d89ef9cd0bdb783a4b59869a4c9211f1567f3e0717f31e92704ed7b1801a33d3252d3 languageName: node linkType: hard @@ -4724,7 +4724,7 @@ __metadata: "@hyperdx/common-utils": "npm:^0.32.0" "@hyperdx/node-opentelemetry": "npm:^0.9.0" "@hyperdx/passport-local-mongoose": "npm:^9.0.1" - "@modelcontextprotocol/sdk": "npm:^1.27.1" + "@modelcontextprotocol/sdk": "npm:^1.32.2" "@opentelemetry/api": "npm:^1.8.0" "@opentelemetry/host-metrics": "npm:^0.35.5" "@opentelemetry/sdk-metrics": "npm:^1.30.1" @@ -4767,7 +4767,7 @@ __metadata: migrate-mongo: "npm:^11.0.0" minimist: "npm:^1.2.7" mongodb: "npm:^6.15.0" - mongoose: "npm:^6.13.10" + mongoose: "npm:^6.13.12" ms: "npm:^2.1.3" nodemon: "npm:^2.0.20" on-headers: "npm:^1.1.0" @@ -6578,11 +6578,11 @@ __metadata: languageName: node linkType: hard -"@modelcontextprotocol/sdk@npm:^1.27.1": - version: 1.29.0 - resolution: "@modelcontextprotocol/sdk@npm:1.29.0" +"@modelcontextprotocol/sdk@npm:^1.32.2": + version: 1.32.2 + resolution: "@modelcontextprotocol/sdk@npm:1.32.2" dependencies: - "@hono/node-server": "npm:^1.19.9" + "@hono/node-server": "npm:^1.19.9 || ^2.0.5" ajv: "npm:^8.17.1" ajv-formats: "npm:^3.0.1" content-type: "npm:^1.0.5" @@ -6607,7 +6607,7 @@ __metadata: optional: true zod: optional: false - checksum: 10c0/7c4bc339205b1652330cd4e6b121cc859079655f2b9c0506bbb15563ba0d07924bda3d949705530532db7f4d2cb86d633dc8f92bc32803d97c7bece2ac63e29f + checksum: 10c0/31d045fe1121242ee7871f5fc9d5dc1f2ad622d9a9750fab5c14d1a1da227dd7225b16df0e8f22783356981255b22f5da84d1f74985df264ad79f2f00cc6ac7b languageName: node linkType: hard @@ -23646,18 +23646,18 @@ __metadata: languageName: node linkType: hard -"mongoose@npm:^6.13.10": - version: 6.13.10 - resolution: "mongoose@npm:6.13.10" +"mongoose@npm:^6.13.12": + version: 6.13.12 + resolution: "mongoose@npm:6.13.12" dependencies: bson: "npm:^4.7.2" kareem: "npm:2.5.1" mongodb: "npm:4.17.2" mpath: "npm:0.9.0" - mquery: "npm:4.0.3" + mquery: "npm:4.0.4" ms: "npm:2.1.3" sift: "npm:16.0.1" - checksum: 10c0/87b28f1535c0250b5fb23e0d8c8da3f36be2942b383a9e2513cd4a88ee75028ebca31c4d9f3b81e8f8381ece518bc8fe41fd41c2da5a36943119a2f8b4a34f4a + checksum: 10c0/07d7ca1c146475408fc79cd90afb89a6ea4da9fcbb1eddda7cb19e7cc81a7be3fa3f580ffc45938b22e3fa47c7f52c7c527ce3df265adac9a80d47d0f7e0c08d languageName: node linkType: hard @@ -23675,12 +23675,12 @@ __metadata: languageName: node linkType: hard -"mquery@npm:4.0.3": - version: 4.0.3 - resolution: "mquery@npm:4.0.3" +"mquery@npm:4.0.4": + version: 4.0.4 + resolution: "mquery@npm:4.0.4" dependencies: debug: "npm:4.x" - checksum: 10c0/771eb00466f2c1a1342737fa0379d50c21bb6c09545d6fa4488a81c096a62548ec2080d53e5ead57c8e19f7354d3315e2403878abfb5a6bc8f3e732236874374 + checksum: 10c0/fe9eb6920768343d3f66aa864f3928856483491e10e13a86f8dbf25c0c4551522061d6966e24023282258feedea2df1669051258aa11b80601298f701b732d0b languageName: node linkType: hard @@ -30441,9 +30441,9 @@ __metadata: linkType: hard "undici@npm:^7.29.0": - version: 7.30.0 - resolution: "undici@npm:7.30.0" - checksum: 10c0/011a321a9198532b0f0504740faa43b9ab8fcc0e4f60104e5c9cb808a61faeb03e4be4aec4f0c65f47913d7c7d9d91591793a6cb9ab843f98ca2c3d711c4a34c + version: 7.30.2 + resolution: "undici@npm:7.30.2" + checksum: 10c0/806e17f14fb49d2b63be314cf2be68efbe105469118b366d19a3cb6fd6686089220c74c1e8e947e6b337a16ff434c10c3860f3e637db314381c4ce8c071c3daf languageName: node linkType: hard