Every page breaches the content security policy, because htmx injects a stylesheet #68

Closed
opened 2026-09-06 17:34:41 +00:00 by tiagoagueda · 0 comments
Owner

What happens

Every page Postulo serves logs a content security policy violation in the browser console:

Applying inline style violates the following Content Security Policy directive
'style-src 'self''. ... The action has been blocked.

Found while driving the passkey flow through a real browser with the production policy on.
It is on the dashboard, the sign-in page and the password reset page too, so it has nothing
to do with passkeys and has been there since htmx was vendored.

Why

htmx ships with includeIndicatorStyles: true, which makes it inject a <style> element
into the head as it starts, carrying the rules for .htmx-indicator. Production sets
style-src 'self' with no unsafe-inline, so the browser refuses it.

The injected rules are redundant: assets/css/app.css already defines .htmx-indicator
and the .htmx-request pair, deliberately, because the policy forbids exactly this.

Why it matters more than a console message

  • The policy is one of the project's stated commitments, and an instance that logs a
    violation on every page has one that is not quite true. Anybody hardening their instance,
    or pointing a reporting endpoint at it, sees noise that means nothing.
  • Real violations hide in it. A browser test that asserts the policy is not breached
    cannot be written while every page breaches it, which is precisely how this went unnoticed.

Fix

Tell htmx not to, with a meta tag in base.html — an attribute, which the policy allows:

<meta name=htmx-config content='{includeIndicatorStyles:false}'>

Then a browser test that visits a few pages with the production policy applied and fails on
any violation logged to the console. That is the part that keeps it fixed.

Classification

Bug, security. Not breaking: the indicator styling is already in Postulo's own stylesheet.

## What happens Every page Postulo serves logs a content security policy violation in the browser console: ``` Applying inline style violates the following Content Security Policy directive 'style-src 'self''. ... The action has been blocked. ``` Found while driving the passkey flow through a real browser with the production policy on. It is on the dashboard, the sign-in page and the password reset page too, so it has nothing to do with passkeys and has been there since htmx was vendored. ## Why htmx ships with `includeIndicatorStyles: true`, which makes it inject a `<style>` element into the head as it starts, carrying the rules for `.htmx-indicator`. Production sets `style-src 'self'` with no `unsafe-inline`, so the browser refuses it. The injected rules are redundant: `assets/css/app.css` already defines `.htmx-indicator` and the `.htmx-request` pair, deliberately, because the policy forbids exactly this. ## Why it matters more than a console message - **The policy is one of the project's stated commitments**, and an instance that logs a violation on every page has one that is not quite true. Anybody hardening their instance, or pointing a reporting endpoint at it, sees noise that means nothing. - **Real violations hide in it.** A browser test that asserts the policy is not breached cannot be written while every page breaches it, which is precisely how this went unnoticed. ## Fix Tell htmx not to, with a meta tag in `base.html` — an attribute, which the policy allows: ```html <meta name=htmx-config content='{includeIndicatorStyles:false}'> ``` Then a browser test that visits a few pages with the production policy applied and fails on any violation logged to the console. That is the part that keeps it fixed. ## Classification Bug, security. Not breaking: the indicator styling is already in Postulo's own stylesheet.
tiagoagueda added this to the 0.2.0 milestone 2026-09-06 17:34:41 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo#68
No description provided.