Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/__tests__/cors-fix.test.ts
Original file line number Diff line number Diff line change
@@ -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);
Comment on lines +1 to +24
});
});
7 changes: 4 additions & 3 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment on lines +196 to +197
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);
Expand Down
Loading