Content Security Policy (CSP)

Content Security Policy (CSP) is a critical defense-in-depth web security standard designed to prevent Cross-Site Scripting (XSS), data injection, and malicious asset loading. Modern strict CSP policies (CSP Level 3) eliminate dangerous directives like 'unsafe-inline' and 'unsafe-eval', enforcing cryptographic validation via hashes or nonces for inline assets.

Coralite provides first-class, build-time and runtime CSP integration. The framework automatically tracks and secures all framework-injected elements—including hydration runtimes, component scripts, import maps, scoped component styles, and development live-reload connections—without requiring developer manual intervention.

Quick Setup #

To enable Content Security Policy in your Coralite project, declare the csp configuration block in your coralite.config.js file using defineConfig:

javascript
Code copied!
  // coralite.config.js
  import { defineConfig } from 'coralite-scripts';
  
  export default defineConfig({
    output: './dist',
    pages: './src/pages',
    templates: './src/templates',
    csp: {
      enabled: true,
      hashAlgorithm: 'sha256',
      injectMeta: true,
      directives: {
        'default-src': ["'self'"],
        'script-src': ["'self'"],
        'style-src': ["'self'"]
      }
    }
  });

Configuration Options #

The csp configuration object accepts the following options:

Option Type Default Description
enabled boolean true Enables or disables CSP header and meta tag generation.
nonce string undefined Cryptographic random nonce for per-request SSR propagation. Activates SSR Nonce Mode when set.
hashAlgorithm 'sha256' | 'sha384' | 'sha512' 'sha256' Hashing algorithm for inline script and style nodes in SSG Hash Mode.
injectMeta boolean true Automatically injects <meta http-equiv="Content-Security-Policy" content="..."> into document <head> during build.
reportOnly boolean false Uses Content-Security-Policy-Report-Only header / meta name instead of enforcing policies.
externalScripts boolean false Bundles runtime scripts into external JavaScript files (assets/js/pages/[page]-[hash].js).
externalStyles boolean false Bundles inline component styles into external CSS files (assets/css/coralite-inline-[hash].css).
directives Record<string, string | string[]> Default directives Custom directive overrides merged into the baseline CSP directives.

Strategy 1: Static Site Generation (SSG) with Automated Hashing #

For statically generated sites (SSG), Coralite inspects all serialized inline <script>, <script type="importmap">, and <style> elements post-render. It automatically calculates base64 cryptographic hashes (e.g. 'sha256-...') and populates the script-src and style-src directives.

Meta Tag Injection #

When injectMeta: true is enabled, Coralite automatically inserts the computed policy directly into the HTML document's <head>:

html
Code copied!
  &lt;meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'sha256-abc...' 'sha256-xyz...'; style-src 'self' 'sha256-123...';"&gt;

Generating HTTP Response Headers for Hosting Platforms #

For hosting environments that support HTTP response headers (such as Netlify, Cloudflare Pages, Vercel, or Nginx), Coralite exposes the computed header string on the build result (result.csp.header). You can generate static header rules directly from build callbacks.

Netlify (_headers file) Example

javascript
Code copied!
  // coralite.config.js
  import fs from 'node:fs/promises';
  import { defineConfig } from 'coralite-scripts';
  
  export default defineConfig({
    output: './dist',
    pages: './src/pages',
    templates: './src/templates',
    csp: { enabled: true, injectMeta: false },
    plugins: [{
      name: 'netlify-headers',
      server: {
        onAfterBuild: async ({ results, app }) => {
          const headerRules = results.map(res => {
            const route = res.path.pathname.replace(/^dist/, '').replace(/index\.html$/, '');
            return `${route}\n  Content-Security-Policy: ${res.csp.header}`;
          }).join('\n\n');
          
          await fs.writeFile('./dist/_headers', headerRules);
        }
      }
    }]
  });

Nginx Configuration Example

text
Code copied!
  # nginx.conf
  server {
    listen 80;
    server_name example.com;
    root /var/www/html;
  
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'sha256-...'; style-src 'self' 'sha256-...'";
  }

Strategy 2: Server-Side Rendering (SSR) with Nonces #

For dynamic Server-Side Rendered (SSR) applications, generating a fresh cryptographic nonce per HTTP request provides optimal protection while enabling CSP Level 3 'strict-dynamic' trust propagation.

Express Middleware Example #

javascript
Code copied!
  import express from 'express';
  import crypto from 'node:crypto';
  import { createCoralite } from 'coralite';
  
  const app = express();
  const coralite = await createCoralite({
    pages: './src/pages',
    components: './src/components',
    csp: { enabled: true }
  });
  
  app.get('*', async (req, res) => {
    // 1. Generate a cryptographic nonce per request
    const nonce = crypto.randomBytes(16).undefined('base64');
  
    // 2. Build the page passing the request nonce
    const results = await coralite.build(req.path, { nonce });
    const result = results[0];
  
    // 3. Set the response header and return HTML
    res.setHeader('Content-Security-Policy', result.csp.header);
    res.send(result.content);
  });
  
  app.listen(3000);

Fastify Integration Example #

javascript
Code copied!
  import Fastify from 'fastify';
  import crypto from 'node:crypto';
  import { createCoralite } from 'coralite';
  
  const fastify = Fastify();
  const coralite = await createCoralite({
    pages: './src/pages',
    components: './src/components',
    csp: { enabled: true }
  });
  
  fastify.get('*', async (request, reply) => {
    const nonce = crypto.randomBytes(16).undefined('base64');
    const results = await coralite.build(request.url, { nonce });
    const result = results[0];
  
    reply.header('Content-Security-Policy', result.csp.header);
    reply.type('text/html').send(result.content);
  });
  
  await fastify.listen({ port: 3000 });

Strategy 3: Zero-Inline External Mode #

If your compliance standard strictly prohibits inline scripts or styles entirely—forbidding inline hashes or nonces—Coralite offers full externalization options via externalScripts and externalStyles.

javascript
Code copied!
  // coralite.config.js
  import { defineConfig } from 'coralite-scripts';
  
  export default defineConfig({
    output: './dist',
    pages: './src/pages',
    templates: './src/templates',
    csp: {
      enabled: true,
      externalScripts: true,
      externalStyles: true,
      directives: {
        'script-src': ["'self'", "'strict-dynamic'"],
        'style-src': ["'self'"]
      }
    }
  });

How Zero-Inline Mode Operates #

Route-Level Customization #

Individual pages can override or disable global CSP configurations using HTML <meta> tags inside their document <head>.

Disabling CSP on a Specific Route #

To disable CSP generation for an isolated route (e.g., a legacy landing page or embedded widget demo), add:

html
Code copied!
  &lt;head&gt;
    &lt;meta name="csp" content="false"&gt;
  &lt;/head&gt;

Overriding Directives per Route #

To declare page-specific directive additions (e.g. allowing video streams or third-party analytics on a single page), pass a JSON object in name="csp-directives":

html
Code copied!
  &lt;head&gt;
    &lt;meta name="csp-directives" content='{"media-src": ["https://stream.example.com"], "connect-src": ["https://api.example.com"]}'&gt;
  &lt;/head&gt;

Development Server & Live-Reload #

When developing locally using coralite-scripts dev (or when mode === 'development'), Coralite automatically appends connect-src 'self' (or connect-src ws: http:) to allow Server-Sent Events (SSE) live-reloading via the /__coralite/rebuild.js route.

This guarantees that enabling strict CSP during local development will never break hot-reloading or terminal error overlays.

Trusted Types & Client Runtime Safety #

Coralite's client-side runtime (e.g., hydration helpers, error overlays, dynamic DOM mounting) is explicitly written to satisfy DOM Sink standards and Content Security Policy Trusted Types. It avoids unsafe sinks such as innerHTML, outerHTML, or string-based style assignments, utilizing safe document.createElement, textContent, and explicit DOM node manipulation routines.

Start Building with Coralite!

Use the scaffolding script to get jump started into your next project with Coralite

Copied commandline!