diff --git a/src/runtime/internal/error.ts b/src/runtime/internal/error.ts index e84dba6021..d8997c5f50 100644 --- a/src/runtime/internal/error.ts +++ b/src/runtime/internal/error.ts @@ -1,5 +1,10 @@ // import ansiHTML from 'ansi-html' -import { send, setResponseHeader, setResponseStatus } from "h3"; +import { + send, + setResponseHeader, + setResponseHeaders, + setResponseStatus, +} from "h3"; import type { NitroErrorHandler } from "nitropack/types"; import { isJsonRequest, normalizeError } from "./utils"; @@ -56,6 +61,18 @@ export default defineNitroErrorHandler( setResponseHeader(event, "Cache-Control", "no-cache"); } + // Security headers + setResponseHeaders(event, { + // Disable the execution of any js + "Content-Security-Policy": "script-src 'none'; frame-ancestors 'none';", + // Prevent browser from guessing the MIME types of resources. + "X-Content-Type-Options": "nosniff", + // Prevent error page from being embedded in an iframe + "X-Frame-Options": "DENY", + // Prevent browsers from sending the Referer header + "Referrer-Policy": "no-referrer", + }); + setResponseStatus(event, statusCode, statusMessage); if (isJsonRequest(event)) { diff --git a/test/tests.ts b/test/tests.ts index 4f2aec0dc4..122e06c735 100644 --- a/test/tests.ts +++ b/test/tests.ts @@ -378,13 +378,20 @@ export function testNitro( }); it("handles errors", async () => { - const { status } = await callHandler({ + const { status, headers } = await callHandler({ url: "/api/error", headers: { Accept: "application/json", }, }); expect(status).toBe(503); + expect(headers).toMatchObject({ + "content-type": "application/json", + "content-security-policy": "script-src 'none'; frame-ancestors 'none';", + "referrer-policy": "no-referrer", + "x-content-type-options": "nosniff", + "x-frame-options": "DENY", + }); }); it.skipIf(isWindows && ctx.preset === "nitro-dev")(