Chrome Extension Content Security Policy (CSP): What You Need to Know
If you’re developing Chrome extensions in 2025, understanding Content Security Policy (CSP) is no longer optional—it’s essential. Since Google’s transition to Manifest V3, CSP restrictions have become significantly more stringent, and inline scripts are systematically blocked by default. This fundamental change has caught many developers off guard, causing runtime errors and rejected extensions in the Chrome Web Store. In this comprehensive guide, we’ll dive deep into Chrome extension CSP requirements, explain why inline scripts are blocked, show you how to configure proper security headers, and provide actionable solutions for common CSP-related challenges.
What Is Content Security Policy (CSP)?
Content Security Policy is a browser security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks. CSP works by specifying which dynamic resources—such as scripts, stylesheets, images, and fonts—can be loaded and executed on a web page or extension page. By defining an allowlist of trusted sources, CSP dramatically reduces the attack surface available to malicious actors.
For Chrome extensions, CSP serves as a critical defense mechanism because extensions operate with elevated privileges. A properly configured CSP for Chrome extensions prevents your extension from loading malicious external resources, executing untrusted scripts, or being exploited by attackers who manage to inject code into your extension’s pages.
The CSP policy is defined through HTTP headers or meta tags and consists of directives that control specific resource types. The most important directives include default-src (the fallback policy), script-src (valid sources for JavaScript), style-src (valid sources for stylesheets), img-src (valid sources for images), and connect-src (valid sources for fetch, XHR, and WebSocket connections).
Why CSP Matters for Chrome Extensions
Chrome extensions handle sensitive data and operate with permissions that regular web pages don’t have. From accessing browser tabs and managing downloads to reading browsing history and modifying web page content, extensions can perform powerful operations that make them attractive targets for attackers. Without a robust CSP configuration, a single vulnerability could allow attackers to hijack your extension’s privileges and compromise user data.
Google has recognized these risks and progressively tightened CSP requirements with each Manifest version. In Manifest V2, developers had more flexibility but also more responsibility. With Manifest V3, Google imposed stricter defaults to protect users from potentially harmful extensions. This means understanding and properly implementing CSP is now a requirement for getting your extension approved in the Chrome Web Store.
The consequences of ignoring CSP can be severe. Extensions that fail to comply with CSP requirements may be rejected during review, experience runtime errors that break functionality, or—worst case—be vulnerable to attacks that harm your users.
Manifest V3 CSP Changes: What Changed?
Manifest V3 introduced several significant changes to how CSP works for Chrome extensions. Understanding these changes is crucial for anyone migrating from Manifest V2 or starting new projects with the current standards.
The Inline Script Ban
The most notable change in Manifest V3 is that inline scripts are completely blocked by default. This means you can no longer use <script> tags with inline JavaScript or inline event handlers like onclick="doSomething()" in your extension’s HTML files. Even script tags without the src attribute will fail to execute.
This change was implemented to prevent a common attack vector where XSS vulnerabilities could lead to arbitrary code execution. By eliminating inline scripts entirely, extensions are forced to use external script files, which can be more easily audited and controlled.
To work around this restriction, you must move all JavaScript code to external files and load them using the src attribute. Instead of writing inline event handlers, you need to use event listeners in your JavaScript files. This approach is more secure and aligns with modern web development best practices.
Stricter Default Policies
Manifest V3 applies stricter default CSP policies to all extension pages, including popups, options pages, background service workers, and tabs opened by the extension. The default policy typically restricts script sources to 'self' (your extension’s files), restricts object sources to 'none', and limits connections to secure origins only.
These restrictions mean you cannot load external scripts from CDNs or third-party domains unless you explicitly allow them in your CSP declaration. While this might seem limiting, it significantly improves security by ensuring your extension only executes code you control.
Background Service Worker Restrictions
Background service workers in Manifest V3 have additional CSP constraints compared to background pages in Manifest V2. Service workers cannot be hosted on external domains—they must be served from your extension’s bundle. This ensures that the background logic of your extension cannot be hijacked by malicious external scripts.
Configuring CSP in Your Manifest V3 Extension
Now that you understand why CSP matters and what changed in Manifest V3, let’s look at how to properly configure CSP in your extension’s manifest file.
The content_security_policy Field
In Manifest V3, you define your CSP using the content_security_policy field in your manifest.json file. This field accepts a CSP policy string that follows the standard Content Security Policy syntax.
Here’s a basic example of a CSP configuration for a Chrome extension:
{
"manifest_version": 3,
"name": "My Secure Extension",
"version": "1.0",
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'none';"
}
}
This configuration restricts scripts to your extension’s files ('self') and prevents any plugin or object content from being loaded ('object-src 'none').
Adding External Script Permissions
If your extension needs to load external scripts—such as analytics libraries or API clients—you need to explicitly allow those domains in your CSP. Here’s how you might configure CSP to allow external scripts from specific trusted sources:
{
"content_security_policy": {
"extension_pages": "script-src 'self' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; connect-src https://api.example.com;"
}
}
Note the inclusion of 'unsafe-inline' in the style-src directive—this is sometimes necessary if your extension uses CSS-in-JS approaches or dynamically generates styles. However, you should minimize the use of 'unsafe-inline' as it weakens your security posture.
CSP for Different Extension Contexts
Understanding that different extension contexts may require different CSP configurations is important. The content_security_policy field in Manifest V3 applies to all extension pages by default. However, you might need different policies for different contexts.
For content scripts that run on web pages, the CSP of the host page takes precedence. This means your content scripts must work within the constraints of whatever CSP the web page implements. In these cases, you cannot modify the CSP of the host page—you must design your content scripts to be compatible with common CSP configurations.
Common CSP Problems and Solutions
Working with CSP in Chrome extensions often involves troubleshooting common issues. Let’s explore the most frequent problems developers encounter and their solutions.
Chrome Extension Inline Script Blocked
The most common issue developers face is the dreaded “Refused to execute inline script” error. This occurs when you try to use inline JavaScript in your extension’s HTML files.
The Problem: Your HTML contains something like this:
<button id="myButton" onclick="handleClick()">Click Me</button>
The Solution: Move the JavaScript to an external file and use addEventListener:
<button id="myButton">Click Me</button>
// popup.js
document.getElementById('myButton').addEventListener('click', handleClick);
This separation of concerns makes your code more maintainable and secure. External scripts can be cached by the browser, audited for security issues, and are protected by CSP.
External Scripts Blocked
Another common issue is blocked external scripts. If you’re loading scripts from CDNs or external domains, you must explicitly whitelist them in your CSP.
The Problem: Your extension tries to load a script from a domain not in your CSP allowlist.
The Solution: Add the domain to your script-src directive:
{
"content_security_policy": {
"extension_pages": "script-src 'self' https://cdn.example.com; object-src 'none';"
}
}
Always ensure external domains you include are trustworthy. Compromised CDN domains can inject malicious code into your extension.
Style Injection Issues
CSS can also be subject to CSP restrictions. If your extension uses dynamic style generation or CSS-in-JS libraries, you might encounter style blocking.
The Solution: Either move styles to external CSS files or allow inline styles with 'unsafe-inline' in your style-src directive (though you should minimize this):
{
"content_security_policy": {
"extension_pages": "script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none';"
}
}
The better approach is to use CSS files and class-based styling, which doesn’t require unsafe-inline permissions.
Font Loading Problems
Loading custom fonts from external sources requires explicit permission in your CSP.
The Solution: Add font-src directive:
{
"content_security_policy": {
"extension_pages": "script-src 'self'; font-src 'self' https://fonts.gstatic.com; style-src 'self'; object-src 'none';"
}
}
Best Practices for Chrome Extension Security Headers
Beyond the basic CSP configuration, implementing security headers properly is crucial for the overall security of your Chrome extension.
Use Strict CSP Settings
Always prefer the strictest CSP that still allows your extension to function. Start with script-src 'self' and object-src 'none' as your baseline, then add only the external resources you genuinely need.
Separate Development and Production CSP
During development, you might need more permissive CSP settings for debugging. Consider using environment variables or build tools to swap CSP configurations between development and production builds.
Regularly Audit Your CSP
As your extension evolves, you might add new features that require additional external resources. Review your CSP regularly to ensure you’re not allowing unnecessary domains and that all allowed domains are still trustworthy.
Use Subresource Integrity
When you must load external scripts, implement Subresource Integrity (SRI) to ensure the fetched resources haven’t been tampered with:
<script src="https://cdn.example.com/library.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous"></script>
SRI ensures that even if an attacker compromises the CDN, they cannot execute modified code in your extension.
Implement Content Script Security
Content scripts run in the context of web pages, which may have their own CSP. Design your content scripts to work within restrictive CSP environments:
- Avoid inline scripts entirely in content scripts
- Use message passing to communicate with your background service worker
- Handle CSP errors gracefully and provide meaningful error messages to users
Testing Your CSP Configuration
Testing is essential to ensure your CSP works correctly and doesn’t break functionality.
Using Chrome DevTools
Chrome DevTools provides excellent CSP debugging capabilities. Open your extension’s popup or options page, then use the DevTools Console tab to see CSP violation messages. The Security tab also shows detailed CSP information.
Automated Testing
Consider adding automated tests that verify your extension’s functionality works with CSP enabled. Tools like Puppeteer can simulate various CSP scenarios and catch issues before they reach production.
Beta Testing
Before releasing to all users, test your extension with a small group of beta testers who can identify CSP-related issues in real-world scenarios.
Migrating from Manifest V2 to Manifest V3 CSP
If you’re migrating an existing extension from Manifest V2 to Manifest V3, you’ll likely encounter CSP challenges.
Audit Inline Scripts
Review all your HTML files for inline scripts and event handlers. Create a comprehensive list of all inline JavaScript that needs to be moved to external files.
Test External Dependencies
Verify that all external scripts, stylesheets, fonts, and API endpoints are whitelisted in your CSP. Update your manifest to include any new domains required by your dependencies.
Update Build Processes
Modify your build process to handle the new file structure. You may need to update bundlers like Webpack or Rollup to output separate files instead of inlined code.
Validate in Development
Test your extension thoroughly in development mode before submitting to the Chrome Web Store. CSP violations that are silently ignored in development may cause runtime failures in production.
Conclusion
Content Security Policy is a fundamental aspect of Chrome extension security in Manifest V3. While the stricter CSP requirements might seem like an obstacle initially, they significantly improve the security posture of your extension and protect your users from potential attacks.
The key takeaways are straightforward: avoid inline scripts entirely, use external files for all JavaScript and CSS, whitelist only trusted external domains, and test your CSP configuration thoroughly. By following these practices, you’ll create extensions that are not only compliant with Chrome Web Store requirements but also resistant to common security vulnerabilities.
Remember, security is not a feature—it’s a foundation. Invest the time to properly implement CSP in your Chrome extensions, and you’ll build software that your users can trust.
This comprehensive guide covers the essential aspects of Chrome extension CSP in Manifest V3. For more information on Chrome extension development, explore our other guides on security best practices, permission management, and performance optimization.