Deploying CSP Policies

Once your policy is validated, deploy it to your web server. This guide covers deployment methods for common platforms.

Before Deploying

Before deploying your CSP policy:

  • ✅ Run a validation scan and ensure it passes
  • ✅ Start with report-only mode to monitor violations
  • ✅ Have a rollback plan (keep your old configuration)
  • ✅ Test on a staging environment first if possible

Required Headers for Violation Reporting

Important: To receive CSP violation reports from all browsers, you need to set two headers:

  • Content-Security-Policy - Contains your policy with report-uri and report-to directives (for Firefox, Safari, and as fallback)
  • Reporting-Endpoints - Defines the endpoint group for the Reporting API (required by Chrome, Edge, Brave)

Browser Support for CSP Reporting

Browser Reporting Mechanism Required Headers
Chrome, Edge, Brave report-to (Reporting API v1) Both CSP + Reporting-Endpoints
Firefox report-uri (legacy) CSP only
Safari report-uri (legacy) CSP only

The Reporting-Endpoints Header

This header defines named endpoints that report-to references. ScriptAttest policies use the endpoint group name csp-endpoint:

Reporting-Endpoints: csp-endpoint="https://scriptattest.com/api/csp/report/YOUR_TOKEN"

Replace YOUR_TOKEN with your site's report token (found in your dashboard under Violations tab).

Deployment Methods

1. HTTP Header (Recommended)

The most secure and recommended method is to set the CSP via HTTP headers. This prevents the policy from being modified by client-side code.

Nginx

Add both headers in your Nginx configuration:

server {
    listen 80;
    server_name example.com;

    # Required for Chrome/Edge/Brave violation reporting
    add_header Reporting-Endpoints 'csp-endpoint="https://scriptattest.com/api/csp/report/YOUR_TOKEN"' always;

    # Your CSP policy (includes both report-to and report-uri)
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; ... report-to csp-endpoint; report-uri https://scriptattest.com/api/csp/report/YOUR_TOKEN" always;
}

For report-only mode:

add_header Content-Security-Policy-Report-Only "default-src 'self'; ..." always;

Apache

Add both headers in your Apache configuration or .htaccess:

<IfModule mod_headers.c>
    # Required for Chrome/Edge/Brave violation reporting
    Header set Reporting-Endpoints "csp-endpoint=\"https://scriptattest.com/api/csp/report/YOUR_TOKEN\""

    # Your CSP policy
    Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; ... report-to csp-endpoint; report-uri https://scriptattest.com/api/csp/report/YOUR_TOKEN"
</IfModule>

Cloudflare

In Cloudflare dashboard, add both headers via Transform Rules:

  1. Go to RulesTransform RulesModify Response Header
  2. Create a new rule
  3. Add header: Reporting-Endpoints with value: csp-endpoint="https://scriptattest.com/api/csp/report/YOUR_TOKEN"
  4. Add header: Content-Security-Policy with your policy string

Vercel

Add both headers in vercel.json:

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Reporting-Endpoints",
          "value": "csp-endpoint=\"https://scriptattest.com/api/csp/report/YOUR_TOKEN\""
        },
        {
          "key": "Content-Security-Policy",
          "value": "default-src 'self'; script-src 'self' https://cdn.example.com; ... report-to csp-endpoint; report-uri https://scriptattest.com/api/csp/report/YOUR_TOKEN"
        }
      ]
    }
  ]
}

Netlify

Add both headers in _headers file:

/*
  Reporting-Endpoints: csp-endpoint="https://scriptattest.com/api/csp/report/YOUR_TOKEN"
  Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; ... report-to csp-endpoint; report-uri https://scriptattest.com/api/csp/report/YOUR_TOKEN

Express.js (Node.js)

Add custom middleware for both headers:

const express = require('express');
const app = express();

const REPORT_TOKEN = 'YOUR_TOKEN';
const REPORT_URL = `https://scriptattest.com/api/csp/report/${REPORT_TOKEN}`;

// Add both headers for all responses
app.use((req, res, next) => {
  // Reporting-Endpoints for Chrome/Edge/Brave
  res.setHeader('Reporting-Endpoints', `csp-endpoint="${REPORT_URL}"`);

  // CSP with both report-to and report-uri
  res.setHeader('Content-Security-Policy',
    "default-src 'self'; script-src 'self' https://cdn.example.com; " +
    `report-to csp-endpoint; report-uri ${REPORT_URL}`
  );
  next();
});

Or with the helmet middleware (note: you'll still need to add Reporting-Endpoints separately):

const helmet = require('helmet');

app.use((req, res, next) => {
  res.setHeader('Reporting-Endpoints', `csp-endpoint="${REPORT_URL}"`);
  next();
});

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "https://cdn.example.com"],
      reportTo: ["csp-endpoint"],
      reportUri: [REPORT_URL],
    },
  },
}));

Django (Python)

Use django-csp middleware:

# settings.py
MIDDLEWARE = [
    'csp.middleware.CSPMiddleware',
    # ... other middleware
]

CSP_DEFAULT_SRC = ["'self'"]
CSP_SCRIPT_SRC = ["'self'", "https://cdn.example.com"]
# ... other directives

2. HTML Meta Tag (Not Recommended)

You can also set CSP via a meta tag in your HTML, but this is less secure:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://cdn.example.com; ...">

Warning: Meta tags can be modified by client-side code and don't support the report-uri directive. Use HTTP headers when possible.

Deployment Workflow

Recommended deployment workflow:

  1. Deploy in report-only mode - Monitor for violations without blocking
  2. Monitor for 24-48 hours - Check violation reports and fix any issues
  3. Approve missing sources - Add any legitimate sources that were missed
  4. Regenerate and redeploy - Update the policy with new sources
  5. Switch to enforce mode - Once confident, switch from report-only to enforce

Updating Policies

When you need to update your policy:

  1. Approve or reject new sources in ScriptAttest
  2. Regenerate the policy
  3. Run a validation scan
  4. Update the header value on your server
  5. Reload your web server configuration

Testing Deployment

After deploying, verify the policy is active:

  • Browser DevTools - Check Network tab → Headers → Response Headers
  • curl - curl -I https://example.com | grep -i content-security-policy
  • Online tools - Use securityheaders.com or similar to verify

Rollback Plan

If something goes wrong:

  1. Keep your old configuration backed up
  2. Have a way to quickly remove or modify the header
  3. Consider using report-only mode initially
  4. Monitor your site's error logs after deployment

Common Issues

Policy Not Applied

Problem: CSP header not showing up in browser.

Solutions:

  • Check web server configuration syntax
  • Ensure header module is enabled (Apache)
  • Clear browser cache
  • Check for conflicting headers

Site Breaks After Deployment

Problem: Resources are blocked and site doesn't work.

Solutions:

  • Switch to report-only mode immediately
  • Check violation reports to identify missing sources
  • Approve missing sources and regenerate
  • Consider temporarily allowing more permissive policy

Best Practices

  • Use HTTP headers - More secure than meta tags
  • Start with report-only - Monitor before enforcing
  • Test thoroughly - Validate before deploying
  • Monitor violations - Check reports regularly
  • Keep policies updated - Regenerate when adding features
  • Document changes - Note why sources were approved

Next Steps

After deploying:

  1. Monitor violations in your dashboard
  2. Review violation reports and fix issues
  3. Switch to enforce mode once confident
  4. Set up scheduled scans for ongoing monitoring