diff --git a/.changeset/busy-weeks-hang.md b/.changeset/busy-weeks-hang.md new file mode 100644 index 000000000..a045aaa41 --- /dev/null +++ b/.changeset/busy-weeks-hang.md @@ -0,0 +1,6 @@ +--- +'@modelcontextprotocol/core': patch +'@modelcontextprotocol/server': patch +--- + +Fix ReDoS vulnerability in UriTemplate regex patterns (CVE-2026-0621) diff --git a/packages/core/src/shared/uriTemplate.ts b/packages/core/src/shared/uriTemplate.ts index 631b65cb0..9dbe65026 100644 --- a/packages/core/src/shared/uriTemplate.ts +++ b/packages/core/src/shared/uriTemplate.ts @@ -225,7 +225,7 @@ export class UriTemplate { switch (part.operator) { case '': - pattern = part.exploded ? '([^/]+(?:,[^/]+)*)' : '([^/,]+)'; + pattern = part.exploded ? '([^/,]+(?:,[^/,]+)*)' : '([^/,]+)'; break; case '+': case '#': @@ -235,7 +235,7 @@ export class UriTemplate { pattern = '\\.([^/,]+)'; break; case '/': - pattern = '/' + (part.exploded ? '([^/]+(?:,[^/]+)*)' : '([^/,]+)'); + pattern = '/' + (part.exploded ? '([^/,]+(?:,[^/,]+)*)' : '([^/,]+)'); break; default: pattern = '([^/]+)'; diff --git a/packages/core/test/shared/uriTemplate.test.ts b/packages/core/test/shared/uriTemplate.test.ts index ec913c0db..5bd54d2cf 100644 --- a/packages/core/test/shared/uriTemplate.test.ts +++ b/packages/core/test/shared/uriTemplate.test.ts @@ -284,5 +284,32 @@ describe('UriTemplate', () => { vars[longName] = 'value'; expect(() => template.expand(vars)).not.toThrow(); }); + + it('should not be vulnerable to ReDoS with exploded path patterns', () => { + // Test for ReDoS vulnerability (CVE-2026-0621) + // See: https://github.com/modelcontextprotocol/typescript-sdk/issues/965 + const template = new UriTemplate('{/id*}'); + const maliciousPayload = '/' + ','.repeat(50); + + const startTime = Date.now(); + template.match(maliciousPayload); + const elapsed = Date.now() - startTime; + + // Should complete in under 100ms, not hang for seconds + expect(elapsed).toBeLessThan(100); + }); + + it('should not be vulnerable to ReDoS with exploded simple patterns', () => { + // Test for ReDoS vulnerability with simple exploded operator + const template = new UriTemplate('{id*}'); + const maliciousPayload = ','.repeat(50); + + const startTime = Date.now(); + template.match(maliciousPayload); + const elapsed = Date.now() - startTime; + + // Should complete in under 100ms, not hang for seconds + expect(elapsed).toBeLessThan(100); + }); }); });