Skip to content

Content Security Policy

How τjs generates and manages CSP headers for your routes.

τjs provides CSP middleware that generates nonce-based Content Security Policy headers and exposes the nonce to your rendering pipeline. This allows inline scripts to execute safely while blocking unauthorised code.

Configure CSP globally in your τjs config:

taujs.config.ts
export default defineConfig({
security: {
csp: {
directives: {
"default-src": ["'self'"],
"script-src": ["'self'"],
"style-src": ["'self'", "'unsafe-inline'"],
"img-src": ["'self'", "data:", "https:"],
},
},
},
});

τjs automatically:

  1. Generates a unique nonce per request
  2. Adds 'nonce-<value>' to script-src if not present
  3. Applies the header to all responses
  4. Passes nonce to React’s rendering pipeline

For each request, τjs:

// Internal - τjs does this automatically
const nonce = crypto.randomBytes(16).toString('base64');
// Adds to script-src
'script-src': ["'self'", "'nonce-abc123...'"]
// Sets header
Content-Security-Policy: script-src 'self' 'nonce-abc123...'
// Passes to renderer
renderStream(res, callbacks, data, location, modules, meta, nonce);

The nonce is automatically applied to:

  • React’s renderToPipeableStream (via nonce option)
  • window.__INITIAL_DATA__ script
  • Client bootstrap script

You do not add nonces manually - τjs handles this.

τjs automatically relaxes CSP for development:

// Your config
{
directives: {
'script-src': ["'self'"],
'style-src': ["'self'"]
}
}
// τjs adds in development
{
'script-src': ["'self'", "'nonce-...'"],
'connect-src': ["'self'", 'ws:', 'http:'], // For Vite/HMR
'style-src': ["'self'", "'unsafe-inline'"] // For hot styles
}

In production, only your directives plus nonce are used:

// Your config
{
'script-src': ["'self'"],
'style-src': ["'self'"]
}
// Result in production
{
'script-src': ["'self'", "'nonce-...'"],
'style-src': ["'self'"]
}

If you ship with development-style directives, τjs logs a warning.

Override or extend CSP for specific routes:

Route directives are merged with global directives:

// Global config
security: {
csp: {
directives: {
'default-src': ["'self'"],
'script-src': ["'self'"]
}
}
}
// Route config
{
path: '/embed',
attr: {
render: 'ssr',
middleware: {
csp: {
directives: {
'frame-ancestors': ["'self'", 'https://trusted.com']
}
}
}
}
}
// Result for /embed
{
'default-src': ["'self'"],
'script-src': ["'self'", "'nonce-...'"],
'frame-ancestors': ["'self'", 'https://trusted.com']
}

Replace global directives entirely:

{
path: '/widget',
attr: {
render: 'ssr',
middleware: {
csp: {
mode: 'replace',
directives: {
'default-src': ["'self'"],
'script-src': ["'self'", 'https://cdn.example.com'],
'style-src': ["'self'", "'unsafe-inline'"]
}
}
}
}
}

Generate directives based on request parameters:

{
path: '/user/:id',
attr: {
render: 'ssr',
middleware: {
csp: {
directives: ({ params, headers }) => ({
'img-src': [
"'self'",
`https://cdn.example.com/users/${params.id}/`
],
'connect-src': ["'self'", 'https://api.example.com']
})
}
}
}
}

Function receives:

  • params - Route parameters
  • headers - Request headers
{
path: '/legacy',
attr: {
render: 'ssr',
middleware: {
csp: false // No CSP header at all
}
}
}

Use when:

  • Legacy HTML that can’t work with CSP
  • Third-party widgets with inline scripts
{
path: '/report',
attr: {
render: 'ssr',
middleware: {
csp: {
disabled: true // Skip route overrides, use global only
}
}
}
}

Test CSP without blocking:

export default defineConfig({
security: {
csp: {
directives: {
"default-src": ["'self'"],
"script-src": ["'self'"],
},
reporting: {
reportOnly: true,
},
},
},
});

Header sent: Content-Security-Policy-Report-Only

{
path: '/experimental',
attr: {
render: 'ssr',
middleware: {
csp: {
reportOnly: true,
directives: {
'script-src': ["'self'", "'strict-dynamic'"]
}
}
}
}
}
export default defineConfig({
security: {
csp: {
directives: {
"default-src": ["'self'"],
"script-src": ["'self'"],
},
reporting: {
endpoint: "/api/csp-violations",
onViolation: (report, req) => {
console.log("CSP violation:", {
documentUri: report["document-uri"],
violatedDirective: report["violated-directive"],
blockedUri: report["blocked-uri"],
});
},
},
},
},
});
reporting: {
endpoint: '/api/csp-violations',
onViolation: (report, req) => {
const violation = report['csp-report'];
// Log to monitoring service
logger.warn({
event: 'csp_violation',
documentUri: violation['document-uri'],
directive: violation['violated-directive'],
blockedUri: violation['blocked-uri'],
userAgent: req.headers['user-agent']
});
// Alert on specific violations
if (violation['blocked-uri'].includes('malicious')) {
alertSecurityTeam(violation);
}
}
}
security: {
csp: {
directives: {
'default-src': ["'self'"],
'script-src': ["'self'", 'https://cdn.example.com'],
'style-src': ["'self'", 'https://cdn.example.com'],
'img-src': ["'self'", 'https://cdn.example.com', 'data:'],
'font-src': ["'self'", 'https://cdn.example.com']
}
}
}
security: {
csp: {
directives: {
'default-src': ["'self'"],
'script-src': [
"'self'",
'https://www.google-analytics.com',
'https://www.googletagmanager.com'
],
'connect-src': [
"'self'",
'https://www.google-analytics.com',
'https://analytics.google.com'
],
'img-src': [
"'self'",
'https://www.google-analytics.com',
'data:'
]
}
}
}
{
path: '/embed',
attr: {
render: 'ssr',
middleware: {
csp: {
directives: {
'frame-src': ["'self'", 'https://www.youtube.com'],
'frame-ancestors': ["'self'", 'https://trusted-partner.com']
}
}
}
}
}
// ✅ Start here
directives: {
'default-src': ["'self'"],
'script-src': ["'self'"],
'style-src': ["'self'"],
'img-src': ["'self'"]
}
// Add sources only when needed

2. Avoid ‘unsafe-inline’ in Production

Section titled “2. Avoid ‘unsafe-inline’ in Production”
// ❌ Defeats CSP purpose
'script-src': ["'self'", "'unsafe-inline'"]
// ✅ Use nonces (τjs does this automatically)
'script-src': ["'self'", "'nonce-...'"]
// ❌ Too broad
'script-src': ["'self'", 'https:']
// ✅ Specific domains
'script-src': ["'self'", 'https://cdn.example.com', 'https://analytics.google.com']
reporting: {
endpoint: '/api/csp-violations',
onViolation: (report, req) => {
monitoringService.track('csp_violation', {
directive: report['violated-directive'],
blockedUri: report['blocked-uri'],
page: report['document-uri']
});
}
}

Use report-only mode initially:

security: {
csp: {
directives: { /* ... */ },
reporting: {
reportOnly: true // Monitor without blocking
}
}
}

After confirming no false positives, switch to enforce mode.