diff --git a/src/__tests__/cors-fix.test.ts b/src/__tests__/cors-fix.test.ts new file mode 100644 index 0000000..f4d67e7 --- /dev/null +++ b/src/__tests__/cors-fix.test.ts @@ -0,0 +1,26 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +describe('CWE-346 CORS fix in server.ts', () => { + const src = readFileSync(join(__dirname, '..', 'server.ts'), 'utf8'); + + it('does not reflect Origin header back into Access-Control-Allow-Origin', () => { + expect(src).not.toMatch(/Access-Control-Allow-Origin['"]\s*,\s*origin\b/); + }); + + it('uses a static wildcard for Access-Control-Allow-Origin', () => { + expect(src).toMatch(/Access-Control-Allow-Origin['"]\s*,\s*['"]\*['"]/); + }); + + it('does not enable Access-Control-Allow-Credentials', () => { + expect(src).not.toMatch(/Access-Control-Allow-Credentials/); + }); + + it('includes a DNS-rebinding Origin/Host check', () => { + expect(src).toMatch(/DNS rebinding protection/i); + }); +}); diff --git a/src/server.ts b/src/server.ts index 4319e3a..148303a 100644 --- a/src/server.ts +++ b/src/server.ts @@ -192,11 +192,12 @@ See documentation for more details on configuring database connections. } } - // CORS headers — only reflect validated origins - res.header('Access-Control-Allow-Origin', origin || 'http://localhost'); + // CORS headers: use a static wildcard origin and do not enable + // cross-origin credentials. The co-hosted workbench uses same-origin + // requests, so credentialed CORS is not required. + res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id'); - res.header('Access-Control-Allow-Credentials', 'true'); if (req.method === 'OPTIONS') { return res.sendStatus(200);