diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 000000000..954d0295b --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-02-18 - [API Security Headers] +**Vulnerability:** Missing Content-Security-Policy (CSP) and Permissions-Policy headers in API responses. +**Learning:** The API server also serves the static UI in production, making CSP crucial for mitigating XSS risks. Also, `bun test` requires explicit mocks for dependencies when `node_modules` are incomplete or path mappings are broken. +**Prevention:** Enforce security headers in the central CORS/headers middleware (`applyCors`) to ensure they apply to all responses. diff --git a/src/api/server.ts b/src/api/server.ts index 489da6da9..60e891df6 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -4240,7 +4240,7 @@ function resolveCorsOrigin(origin?: string): string | null { return null; } -function applyCors( +export function applyCors( req: http.IncomingMessage, res: http.ServerResponse, ): boolean { @@ -4268,6 +4268,14 @@ function applyCors( res.setHeader("X-Frame-Options", "DENY"); res.setHeader("X-XSS-Protection", "1; mode=block"); res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin"); + res.setHeader( + "Content-Security-Policy", + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' ws: wss: https:; media-src 'self' blob:; frame-ancestors 'none'; upgrade-insecure-requests", + ); + res.setHeader( + "Permissions-Policy", + "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), payment=(), usb=()", + ); return true; }