Add security headers and proxy error handling to Hono server

Every response gets X-Frame-Options, X-Content-Type-Options, and
Referrer-Policy (SEC-07/FE-08). Backend proxy failures now return a
logged 502 instead of an opaque uncaught error (FE-23).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-06-09 19:13:32 -06:00
parent 3a357e4f0b
commit bebd7b563e

View File

@@ -324,6 +324,27 @@ class SuppressRenderToolTextMiddleware extends (Middleware as any) {
const app = new Hono();
// Security headers on every response. Responses returned by fetch() (the
// backend proxy) carry immutable headers, so rebuild the Response instead of
// mutating in place.
const SECURITY_HEADERS: Record<string, string> = {
"X-Frame-Options": "DENY",
"X-Content-Type-Options": "nosniff",
"Referrer-Policy": "strict-origin-when-cross-origin",
};
app.use("*", async (c, next) => {
await next();
const res = c.res;
const headers = new Headers(res.headers);
for (const [k, v] of Object.entries(SECURITY_HEADERS)) headers.set(k, v);
c.res = new Response(res.body, {
status: res.status,
statusText: res.statusText,
headers,
});
});
app.all("/api/copilotkit/*", async (c) => {
const cookieHeader = c.req.header("cookie") ?? "";
const match = cookieHeader.match(/(?:^|;\s*)ws_token=([^;]+)/);
@@ -398,7 +419,12 @@ const proxyToBackend = async (c: import("hono").Context) => {
// @ts-expect-error undici requires duplex for streamed bodies
init.duplex = "half";
}
return fetch(target, init);
try {
return await fetch(target, init);
} catch (err) {
console.error(`[proxy] ${method} ${url.pathname} → backend failed:`, err);
return c.json({ error: "Backend unavailable" }, 502);
}
};
app.all("/api/v1/*", proxyToBackend);