feat(security): CSP and hardening headers with upload serving

Implement Content-Security-Policy headers and strict content-type handling
for non-API responses, with x-content-type-options applied to all routes.
Adds security-headers test suite to verify header presence.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
marcuspaico
2026-08-17 16:06:05 -07:00
parent 1aa600adfc
commit 876aa0f181
2 changed files with 35 additions and 0 deletions

View File

@@ -8,9 +8,18 @@ import { settingsRoutes } from "./routes/settings";
export type Deps = { db: Db; key: Buffer; dataDir: string; llmFetch?: typeof fetch };
const PUBLIC = new Set(["/api/health", "/api/me", "/api/setup", "/api/login"]);
const CSP = "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'";
export function createApp(deps: Deps) {
const app = new Hono();
app.use("*", async (c, next) => {
await next();
c.header("x-content-type-options", "nosniff");
if (!c.req.path.startsWith("/api/")) {
c.header("content-security-policy", CSP);
c.header("referrer-policy", "no-referrer");
}
});
app.get("/api/health", (c) => c.json({ ok: true }));
app.use("/api/*", async (c, next) => {
if (PUBLIC.has(c.req.path)) return next();