Strengthening XSS Protection: Nonce-Based CSP in v0.1.126
Strengthening XSS Protection: Nonce-Based CSP in v0.1.126
Security advisory SEC-11 — This post explains the Content Security Policy hardening shipped in v0.1.126 and what it means for platform security.
The Problem
Prior to v0.1.126, the platform's Content-Security-Policy (CSP) HTTP response header was configured as follows (simplified):
Content-Security-Policy:
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
While a CSP header was present, these two directives completely undermined its value:
| Directive | Risk |
|---|---|
'unsafe-inline' in script-src | Allows inline <script> blocks and javascript: URIs — the primary XSS attack vector |
'unsafe-eval' in script-src | Allows eval(), new Function(), and similar dynamic code execution |
'unsafe-inline' in style-src | Allows inline styles, enabling CSS-based data exfiltration attacks |
For a platform that screens individuals and entities against UK sanctions lists and handles sensitive compliance data, this represented an unacceptable risk. An XSS vulnerability anywhere in the application would have allowed an attacker to execute arbitrary JavaScript in a user's browser with no CSP barrier.
The Fix
Nonce-Based CSP via Next.js 15 Middleware
v0.1.126 replaces the weak static CSP with a nonce-based CSP using Next.js 15's built-in middleware support.
A cryptographically random nonce is generated per-request by middleware and injected into both the CSP header and any legitimate <script> and <style> tags. The browser will only execute scripts that carry the correct nonce — inline scripts injected by an attacker will not have the nonce and will be blocked.
Content-Security-Policy:
script-src 'self' 'nonce-<random-per-request>';
style-src 'self' 'nonce-<random-per-request>';
unsafe-eval has been removed entirely. This required eliminating all eval() and new Function() usage from the application codebase — a prerequisite for this directive to be safely dropped.
Why Nonce-Based Rather Than Hash-Based?
Next.js applications typically render dynamic content, making static hash-based CSPs impractical to maintain — any change to an inline script would require a new hash to be computed and deployed. Nonce-based CSP generates a fresh token per request, making it compatible with dynamic rendering while providing equivalent security guarantees.
Impact
- XSS attacks are now actively blocked at the browser level. Even if an attacker were able to inject a
<script>tag into a page, it would be refused execution by the browser's CSP enforcement. - No
eval()in production — dynamic code execution is fully eliminated, reducing the application's attack surface further. - Inline styles from untrusted sources are blocked, preventing CSS-based data exfiltration.
Relevance to Compliance Operations
This platform is used by UK compliance teams to screen against OFSI consolidated lists. Users handle sensitive personal and entity data. Protecting the integrity of the client-side application is not optional — it is a baseline security requirement for any platform operating in a regulated environment. SEC-11 brings the CSP configuration in line with that obligation.
File Changed
next.config.ts— Content-Security-Policy header definition updated to nonce-based configuration