From 53d0b58ebf3468bd161dcfcdc67cd66b6508e9f8 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 25 Mar 2026 04:47:29 -0500 Subject: [PATCH] fix(app): hash inline script for csp --- packages/opencode/src/server/server.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 7ead4df8a3..e4c98c609e 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -1,3 +1,4 @@ +import { createHash } from "node:crypto" import { Log } from "../util/log" import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi" import { Hono } from "hono" @@ -47,6 +48,9 @@ import { lazy } from "@/util/lazy" // @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85 globalThis.AI_SDK_LOG_WARNINGS = false +const csp = (hash = "") => + `default-src 'self'; script-src 'self' 'wasm-unsafe-eval'${hash ? ` 'sha256-${hash}'` : ""}; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:` + export namespace Server { const log = Log.create({ service: "server" }) @@ -506,10 +510,13 @@ export namespace Server { host: "app.opencode.ai", }, }) - response.headers.set( - "Content-Security-Policy", - "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:", - ) + const match = response.headers.get("content-type")?.includes("text/html") + ? (await response.clone().text()).match( + /]*\bsrc\s*=)[^>]*\bid=(['"])oc-theme-preload-script\1[^>]*>([\s\S]*?)<\/script>/i, + ) + : undefined + const hash = match ? createHash("sha256").update(match[2]).digest("base64") : "" + response.headers.set("Content-Security-Policy", csp(hash)) return response }) }