All Docs
FeaturesCalmony Sanctions MonitorUpdated March 12, 2026

Hardening Our Content Security Policy: Removing unsafe-inline and unsafe-eval

Hardening Our Content Security Policy: Removing unsafe-inline and unsafe-eval

Release: v0.1.105 | Control: SEC-11 | Category: Infrastructure Security


Background

A Content-Security-Policy (CSP) header is one of the most effective browser-enforced defences against Cross-Site Scripting (XSS) attacks. By declaring exactly which scripts, styles, and resources a page is permitted to load, a well-configured CSP stops injected code from executing — even if an attacker manages to get malicious content into the page.

However, two directives completely undermine this protection:

  • 'unsafe-inline' in script-src — allows any inline <script> block on the page to run, including attacker-injected ones.
  • 'unsafe-eval' in script-src — allows JavaScript to evaluate arbitrary strings as code via eval(), new Function(), and similar APIs.

Prior to this release, the platform's next.config.ts included both of these directives. For a compliance platform handling sensitive screening data, this was an unacceptable risk.


What We Fixed

1. Nonce-based CSP via Next.js 15 Middleware

Rather than allowing all inline scripts, the server now generates a cryptographic nonce (a random, single-use token) for every HTTP request. This nonce is:

  1. Injected into the Content-Security-Policy response header.
  2. Added as an attribute to every legitimate <script> and <style> tag the server renders.

The browser will only execute inline scripts and styles that carry a matching nonce. An attacker who injects a <script> tag cannot know the nonce for that request, so their code is blocked.

# Example CSP header (nonce-based)
Content-Security-Policy:
  script-src 'nonce-abc123xyz' 'strict-dynamic';
  style-src  'nonce-abc123xyz';

This approach is the recommended path for Next.js 15 applications.

2. Elimination of eval() Usage

'unsafe-eval' is only required when application code calls eval(), new Function(), setTimeout(string), or similar dynamic evaluation APIs. As part of this release, all such patterns were audited and removed from the codebase. With no legitimate eval() usage remaining, there is no reason to keep the directive.

3. Removal of style-src 'unsafe-inline'

Inline styles are a lesser-known XSS vector. Attackers can use injected CSS to exfiltrate data (e.g. via background-image: url(...) triggered by attribute selectors) or to manipulate UI elements to deceive users. Removing 'unsafe-inline' from style-src closes this attack surface.


Why This Matters for a Compliance Platform

This platform is used by UK compliance teams to screen individuals and entities against the OFSI consolidated sanctions list. The data processed is sensitive and the decisions made carry regulatory weight. A successful XSS attack could:

  • Exfiltrate screening results or personal data to an attacker-controlled server.
  • Silently modify screening outcomes displayed to an operator.
  • Hijack authenticated sessions.

A permissive CSP was effectively a safety net with a large hole in it. This release closes that hole.


Files Changed

FileChange
next.config.tsCSP header updated to nonce-based policy; unsafe-inline and unsafe-eval removed from script-src and style-src

For Self-Hosted Deployments

If you run a self-hosted instance and maintain a custom next.config.ts, you should update your CSP configuration to match. The minimum recommended script-src policy for a Next.js 15 application without unsafe-inline or unsafe-eval is:

// next.config.ts (illustrative)
const cspHeader = `
  default-src 'self';
  script-src 'nonce-{NONCE}' 'strict-dynamic';
  style-src 'nonce-{NONCE}';
  img-src 'self' data:;
  font-src 'self';
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none';
  upgrade-insecure-requests;
`;

The nonce value ({NONCE}) must be generated per-request in your Next.js middleware and propagated to both the header and every <script>/<style> tag. See the Next.js CSP documentation for the full middleware pattern.


Further Reading