Content Security Policy (CSP) is one of the most powerful security mechanisms available to protect WordPress sites from cross-site scripting (XSS) attacks, code injection, and other malicious activities. This advanced security feature allows you to control which resources can be loaded and executed on your website, creating a robust defense layer that complements traditional security measures.
Understanding Content Security Policy
Content Security Policy is an HTTP response header that instructs browsers which sources of content are trustworthy for your website. When properly configured, CSP prevents browsers from executing malicious scripts injected through vulnerabilities, even if attackers manage to insert code into your database or files.
The CSP header works by defining a whitelist of approved sources for various types of content including scripts, stylesheets, images, fonts, and other resources. When a browser encounters content from an unapproved source, it blocks the resource and optionally reports the violation.
Modern browsers support CSP Level 2 and Level 3 specifications, providing extensive protection capabilities. According to Mozilla’s compatibility data, over 95% of users have browsers that support core CSP features, making it a practical security enhancement for most WordPress sites.
Core CSP Directives Explained
Understanding CSP directives is crucial for implementing effective policies. The default-src directive serves as a fallback for other directives, establishing the baseline policy. For example, default-src 'self' restricts all content to your own domain unless overridden by specific directives.
The script-src directive controls JavaScript execution and is typically the most critical for preventing XSS attacks. A policy like script-src 'self' https://cdn.example.com allows scripts only from your domain and the specified CDN.
The style-src directive manages CSS sources, while img-src controls image loading. The font-src directive governs font file sources, essential for custom typography. The connect-src directive restricts URLs for AJAX requests, WebSocket connections, and EventSource connections.
For embedded content, frame-src controls iframe sources, crucial for preventing clickjacking and unauthorized embeds. The media-src directive manages audio and video sources, while object-src controls plugins like Flash (typically set to 'none' in modern sites).
Implementing CSP in WordPress via .htaccess
For Apache-based WordPress installations, adding CSP headers through .htaccess provides server-level implementation. Add this configuration to your root .htaccess file:
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-src 'self'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self';"
</IfModule>This basic policy allows same-origin resources and includes 'unsafe-inline' for inline scripts and styles, which many WordPress themes require. While not the most secure configuration, it provides a starting point that won’t immediately break most sites.
For production environments, gradually tighten this policy by removing 'unsafe-inline' and implementing nonce-based or hash-based approaches for inline content.
Nginx CSP Configuration
For Nginx-powered WordPress sites, add CSP headers in your server configuration file or location block:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-src 'self'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self';" always;
The always parameter ensures the header is sent even for error responses, maintaining consistent security coverage across all HTTP response codes.
Plugin-Based CSP Implementation
The HTTP Headers plugin provides a user-friendly interface for adding security headers including CSP without editing server configuration files. After installing from the WordPress repository, navigate to Settings > HTTP Headers to configure your policy.
The Really Simple SSL plugin also includes CSP functionality in its premium version, offering pre-configured policies and easy management through the WordPress dashboard.
For programmatic control, implement CSP headers using WordPress hooks:
function add_csp_header() {
$csp = "default-src 'self'; ";
$csp .= "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; ";
$csp .= "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; ";
$csp .= "font-src 'self' https://fonts.gstatic.com; ";
$csp .= "img-src 'self' data: https:; ";
$csp .= "connect-src 'self'; ";
$csp .= "frame-src 'self' https://www.youtube.com; ";
$csp .= "object-src 'none'; ";
$csp .= "base-uri 'self';";
header("Content-Security-Policy: " . $csp);
}
add_action('send_headers', 'add_csp_header');This approach allows dynamic CSP generation based on conditions, user roles, or page types.
Implementing Nonce-Based CSP
Nonces (numbers used once) provide a secure alternative to 'unsafe-inline' by allowing specific inline scripts while blocking others. WordPress 5.7+ includes built-in support for script and style nonces.
Generate and implement nonces in your theme’s functions.php:
function add_csp_nonce() {
$nonce = base64_encode(random_bytes(16));
// Store nonce for use in CSP header
global $csp_nonce;
$csp_nonce = $nonce;
// Add nonce to inline scripts
add_filter('script_loader_tag', function($tag, $handle) use ($nonce) {
if (strpos($tag, '<script') !== false) {
$tag = str_replace('<script', "<script nonce='{$nonce}'", $tag);
}
return $tag;
}, 10, 2);
// Add nonce to inline styles
add_filter('style_loader_tag', function($tag, $handle) use ($nonce) {
if (strpos($tag, '<style') !== false) {
$tag = str_replace('<style', "<style nonce='{$nonce}'", $tag);
}
return $tag;
}, 10, 2);
}
add_action('init', 'add_csp_nonce');
function send_csp_with_nonce() {
global $csp_nonce;
if (!isset($csp_nonce)) return;
$csp = "default-src 'self'; ";
$csp .= "script-src 'self' 'nonce-{$csp_nonce}'; ";
$csp .= "style-src 'self' 'nonce-{$csp_nonce}';";
header("Content-Security-Policy: " . $csp);
}
add_action('send_headers', 'send_csp_with_nonce');This implementation generates a cryptographically secure random nonce for each page load and applies it to inline scripts and styles.
CSP Reporting and Monitoring
CSP’s reporting capabilities help identify violations and refine policies. Implement reporting using the report-uri directive:
function add_csp_with_reporting() {
$csp = "default-src 'self'; ";
$csp .= "script-src 'self' 'unsafe-inline'; ";
$csp .= "report-uri /csp-violation-report-endpoint/;";
header("Content-Security-Policy: " . $csp);
}
add_action('send_headers', 'add_csp_with_reporting');Create an endpoint to receive violation reports:
function csp_violation_report_endpoint() {
if ($_SERVER['REQUEST_URI'] === '/csp-violation-report-endpoint/') {
$report = file_get_contents('php://input');
error_log('CSP Violation: ' . $report);
http_response_code(204);
exit;
}
}
add_action('init', 'csp_violation_report_endpoint');Report-Only Mode for Testing
Before enforcing CSP, use Content-Security-Policy-Report-Only to test without breaking functionality:
function add_csp_report_only() {
$csp = "default-src 'self'; script-src 'self'; report-uri /csp-violations/";
header("Content-Security-Policy-Report-Only: " . $csp);
}
add_action('send_headers', 'add_csp_report_only');This header monitors violations without blocking content, allowing you to identify issues before enforcement.
Handling Third-Party Resources
WordPress sites frequently use external resources requiring CSP accommodation. For Google Fonts, update your policy:
font-src 'self' https://fonts.gstatic.com;
style-src 'self' https://fonts.googleapis.com;
For Google Analytics:
script-src 'self' https://www.google-analytics.com https://ssl.google-analytics.com;
connect-src 'self' https://www.google-analytics.com;
For YouTube embeds:
frame-src 'self' https://www.youtube.com https://www.youtube-nocookie.com;
Page Builder Compatibility
Popular page builders like Elementor and Divi rely heavily on inline scripts and styles. For compatibility while maintaining security:
function conditional_csp() {
// Relaxed CSP for admin and editors
if (current_user_can('edit_posts')) {
$csp = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';";
} else {
// Strict CSP for visitors
$csp = "default-src 'self'; script-src 'self'; style-src 'self';";
}
header("Content-Security-Policy: " . $csp);
}
add_action('send_headers', 'conditional_csp');This approach maintains strict security for visitors while allowing necessary flexibility for content editors.
Best Practices and Recommendations
Start with a permissive policy using Report-Only mode, monitor violations for at least two weeks across different pages and user scenarios, then gradually tighten restrictions. Avoid 'unsafe-inline' and 'unsafe-eval' in production policies when possible.
Minimize whitelisted domains to reduce attack surface. Regularly audit your CSP configuration as themes, plugins, and third-party integrations change. Use the Google CSP Evaluator to analyze your policy for common security issues.
Implement different policies for admin areas versus public pages, as admin functionality often requires more permissive policies. Document your CSP configuration and the reasoning behind specific directives for future reference.
Testing tools like Mozilla Observatory and Security Headers provide comprehensive CSP analysis and recommendations. Browser developer consoles display CSP violations in real-time, essential for debugging.
By implementing Content Security Policy thoughtfully and incrementally, WordPress sites gain significant protection against XSS and injection attacks while maintaining compatibility with necessary functionality and third-party integrations.
External Links
- Content Security Policy (MDN)
- CSP Quick Reference
- Google CSP Evaluator
- OWASP CSP Cheat Sheet
- Security Headers Plugin
Call to Action
Secure your site with bulletproof backups! Backup Copilot Pro offers automated security audits, malware scanning before backups, and instant recovery—try it free!

