Content Security Policy in jekcms: What It Sends and How to Tighten It

What the CSP header jekcms sends by default restricts, what it deliberately leaves open, and how to narrow the policy step by step on your own site.

Content Security Policy in jekcms: What It Sends and How to Tighten It, jekcms blog cover

What the CSP header jekcms sends by default restricts, what it deliberately leaves open, and how to narrow the policy step by step on your own site.

jekcms sends a Content Security Policy (CSP) header out of the box. It is not a strict template that locks everything down. It restricts the thing that matters most, which sources may run scripts on the page, and deliberately leaves the rest open. This post explains what is in the header, why it is built that way and how to narrow it on your own site.

The Default Header

The header is sent from the .htaccess file in the root folder. Split into lines for readability:

Content-Security-Policy:
  base-uri 'self';
  object-src 'none';
  frame-ancestors 'self';
  script-src 'self' 'unsafe-inline'
    https://*.googlesyndication.com https://*.google.com
    https://*.google-analytics.com https://*.googletagmanager.com
    https://*.googleadservices.com https://*.googleapis.com
    https://*.gstatic.com https://*.doubleclick.net
    https://news.google.com https://*.adtrafficquality.google
    https://fundingchoicesmessages.google.com
    https://cdn.jsdelivr.net https://cdnjs.cloudflare.com
    https://connect.facebook.net https://static.cloudflareinsights.com
  • base-uri 'self': Stops an injected <base> tag from pointing relative addresses at another domain.
  • object-src 'none': Turns off Flash and similar plugin content entirely.
  • frame-ancestors 'self': Stops the site from being framed by another site, which blocks clickjacking. An X-Frame-Options: SAMEORIGIN header is sent for the same purpose.
  • script-src: Scripts can load only from the site itself and the listed domains.

Why There Is No default-src

The header deliberately has no default-src. That directive becomes the fallback rule for every resource type not listed separately: fonts, images, connections, frames. With default-src 'self', Google Fonts, payment pages, Google sign-in windows and analytics requests would all stop working unless each was added to the allowlist. Every site uses different services, so no single ready-made list fits everyone. The default policy therefore restricts script execution, which is where XSS does its real damage, and leaves the other resource types to the site owner.

Why unsafe-inline Stays

script-src includes 'unsafe-inline', and that is a deliberate decision too. There are two reasons:

  1. The custom header code setting in the panel prints the verification and tracking snippets the site owner pastes in, exactly as they are. Those snippets cannot be marked with a one-time key (nonce); trying to would break the feature.
  2. Themes and core templates contain inline scripts.

Moving to a nonce-based policy requires solving both first. It is an open item on the list.

'unsafe-eval', on the other hand, is not in the header. Neither jekcms's own code, nor the libraries the panel uses, nor Google's and Facebook's ad and analytics scripts need eval().

Wildcards on Google Domains

The Google domains in the list take the form *.google.com. AdSense, Analytics and Tag Manager scripts load from new subdomains over time, and a hand-written list can quietly break ads after a while. The wildcard removes that maintenance burden in exchange for a wider allowance. If your site runs no ads or analytics, you can remove those domains from your own policy.

Tightening It on Your Own Site

If you want a stricter policy, work in this order:

  1. Report first. Send the new policy as Content-Security-Policy-Report-Only with a report-uri pointing at an address you control. jekcms has no built-in endpoint for collecting violations. Wait at least a week; weekend traffic can exercise different pages.
  2. List the sources you actually use. Fill in style-src, img-src, font-src, connect-src and frame-src from the reports, and add default-src 'self' last.
  3. Serve fonts yourself. The bundled themes load fonts from Google Fonts. If you serve the fonts from your own site, you no longer need to allow fonts.googleapis.com and fonts.gstatic.com, and visitor data does not go to a third party.
  4. Test the panel too. The admin panel loads different scripts from the front end (the editor, the media picker). Do not stop after checking the public pages.

If you change the header in .htaccess, remember that a jekcms update may refresh that file. Keep a copy of your change.

Common Mistakes

  • Adding 'unsafe-eval' because one library uses eval(). Pick a different library if you can.
  • Using shortcuts such as img-src https: that allow any HTTPS source. This makes the image directive meaningless.
  • Forgetting connect-src. AJAX requests break silently and some panel screens stop working.
  • Skipping the report-only stage and enforcing the policy straight away.

Written by

Celil Uyanıkoğlu

Computer engineer with 25+ years in IT. He builds jekcms and runs his own network of content sites on it - every guide published here is tried on those live installs first.

See all posts →

Choose a Licence

Annual licence with a discounted first year; updates and support included. Setup in 30 minutes.

View Pricing
  • Setup and live in 30 minutes
  • 14 professional themes
  • AVIF/WebP image optimization
  • Automatic SEO - Sitemap, Schema.org
  • ZeroTrack cookieless analytics

Be the first to know

New features, release notes and CMS guides. We send a couple of emails a month.