fix(csp): allow blob: stylesheets in style-src for the reader

Every /readers load logged a CSP violation: foliate-js injects its
reader-generated stylesheets as blob: URLs, and style-src only allowed
'self' 'unsafe-inline' — so the sheet was refused and selection/
highlight styling inside the reader rode on nothing.

blob: was already granted for img-src, font-src, and frame-src for
exactly this reader content; style-src now matches. The content is
app-generated at runtime (no cross-origin input), script-src is
untouched, and the strict script hash allow-list keeps its guarantee.

Pinned by TestThemeFlashGuardHashMatchesCSP (script-src only — the
style-src addition doesn't interact) and TestGoSourcesAreCSPSafe.
This commit is contained in:
John O'Keefe committed 2026-11-02 09:31:58 -05:00
1 parent 2df6f8e55c
commit 71b171bf72
1 file changed
+5 -2
+5 -2
View File
@@ -41,10 +41,13 @@ func SecurityHeadersMiddleware() echo.MiddlewareFunc {
// the component and asserts the hash matches.
//
// style-src keeps 'unsafe-inline' for htmx-injected styles and
// Alpine :style attribute writes.
// Alpine :style attribute writes, plus blob: for the
// reader-generated stylesheets foliate injects at open time
// (blocked since the CSP migration — every /readers load
// logged a violation; selection/highlight styling rode on it).
// font/img blob: — the reader renders EPUB-embedded fonts and
// images from blob: URLs inside the foliate content frame.
c.Response().Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' "+ScriptHashThemeFlashGuard+"; style-src 'self' 'unsafe-inline'; img-src 'self' data: https: blob:; font-src 'self' data: blob:; frame-src 'self' blob:")
c.Response().Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' "+ScriptHashThemeFlashGuard+"; style-src 'self' 'unsafe-inline' blob:; img-src 'self' data: https: blob:; font-src 'self' data: blob:; frame-src 'self' blob:")
c.Response().Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
c.Response().Header().Set("Permissions-Policy", "geolocation=(), microphone=(), camera=()")