diff --git a/src/http-transport-security.test.ts b/src/http-transport-security.test.ts index 00b6e24..65f5b32 100644 --- a/src/http-transport-security.test.ts +++ b/src/http-transport-security.test.ts @@ -1,4 +1,5 @@ import { describe, it, expect, vi } from 'vitest'; +import request from 'supertest'; import { EventEmitter } from 'node:events'; import fs from 'node:fs'; import https from 'node:https'; @@ -1606,4 +1607,18 @@ describe('HttpTransport security behavior (no listen)', () => { else process.env.MCP4_SSL_KEY_FILE = originalKey; } }); + + it('sets security headers (X-Content-Type-Options, X-Frame-Options, CSP)', async () => { + const transport = createTransport(); + const app = (transport as any).app; + + const res = await request(app).get('/health'); + + expect(res.statusCode).toBe(200); + expect(res.headers['x-content-type-options']).toBe('nosniff'); + expect(res.headers['x-frame-options']).toBe('DENY'); + expect(res.headers['content-security-policy']).toBe("default-src 'none'; frame-ancestors 'none'"); + + await transport.stop(); + }); }); diff --git a/src/http-transport.ts b/src/http-transport.ts index f3b67f9..91842a3 100644 --- a/src/http-transport.ts +++ b/src/http-transport.ts @@ -127,6 +127,14 @@ export class HttpTransport { next(); }); + // Security: Set default security headers + this.app.use((_req: Request, res: Response, next: NextFunction) => { + res.setHeader('X-Content-Type-Options', 'nosniff'); + res.setHeader('X-Frame-Options', 'DENY'); + res.setHeader('Content-Security-Policy', "default-src 'none'; frame-ancestors 'none'"); + next(); + }); + // JSON body parser this.app.use(express.json());