tracking for shynet analytics when Javascript is disabled Creating Content Security Policy in SvelteKit — Hugo Sum
Hugo Sum

Creating Content Security Policy in SvelteKit

What is Content Security Policy (CSP)?

In a nutshell, Content Security Policy (CSP) is a list of trusted origins which only their resources can be loaded on your website once defined. This is a security feature for preventing attacks such as cross-site scripting (XSS) and data injection.

CSP can be defined through HTTP response headers Content-Security-Policy and Content-Security-Policy-Report-Only or meta tags with <meta http-equiv>.

Setting up Content Security Policy in SvelteKit

SvelteKit provides CSP support out of the box. We just need to define the policy we want through kit.csp, and SvelteKit will generate the corresponding hash or nonce for its inline style and scripts, and policies as <meta http-equiv> tag in HTML.

Initially I defined my CSP based on the basic non-strict policy from OWASP. default-src directive would be used as a fallback for most unspecified directives, except a few exceptions such as frame-ancestors and form-action directive. The values of a directive are the allowed origins, and self represents the same origin as your website.

By defining our policies in kit.csp.reportOnly instead of kit.csp.directives, browsers would not block non-compliant resources but only log violations or make a POST request to the endpoint defined in report-uri. With that information, you can discover resources your website depending on, and gradually tighten your security policies without breaking anything, by moving your security policies from kit.csp.reportOnly to kit.csp.directives.

svelte.config.js
const config = {
  kit: {
    csp: {
      // NOTE without setting a truthy value for kit.csp.directives, SvelteKit would not do anything for CSP
      directives: {},
      reportOnly: {
        "default-src": ["self"],
        'frame-ancestors': ['self'],
        'form-action': ['self'],
        'report-uri': ['/'],
      },
    },
  },
};

I have created a minimal SvelteKit project with these content security policies defined, so you can play around yourself.

Dealing with CSP violations in SvelteKit

The above configuration should work for most of the SvelteKit projects. From time to time you might encounter packages that violates your CSP. For example, on this website I use Grafana Faro for tracking performance my website. The SDK for this service, @grafana/faro-web-sdk used a package contains eval() in its code, I then notice the following log in my console.

Content-Security-Policy: (Report-Only policy) The page’s settings would block a JavaScript eval (script-src) from being executed because it violates the following directive: “script-src 'self' 'nonce-ewcvSmSO/2WM8RPgzlYn3A==' (Missing 'unsafe-eval')

An option to address this is to add unsafe-eval to script-src directive as suggested, but this is a global setting for my website, not only for this package. We won’t get much benefit from CSP if we had used unsafe-eval or unsafe-inline.

The other option is we move the policies to kit.csp.reportOnly for reporting violations only, and we monitor those violations reports to verify our website is secure or not. You could host a server that receives and converts the POST payload sent by Reporting API from browsers to metrics understandable by tools such as Prometheus or OpenTelemetry, and then set up alerting rules to monitor content security policy’s violations. This approach requires more work in the back end, but it saves you from refactoring code or switch packages in your SvelteKit project.

From my research, I found go-csp-collector for collecting the reports, and it seems to be a good starting point for building your monitoring system.

Hugo Sum

A Hongkonger living in the UK. The only thing I know is there is so much I don't know.

Enjoy reading my blog?

Subscribe to a monthly newsletter and join my adventure on software development.

© 2025 Hugo Sum. All Rights Reserved.