feat: Add Content-Security-Policy meta tag for GitHub Pages#596
feat: Add Content-Security-Policy meta tag for GitHub Pages#596RichardSlater wants to merge 2 commits intomasterfrom
Conversation
Add CSP header via meta tag since GitHub Pages doesn't support HTTP headers. Changes: - Add headTags configuration with CSP meta tag - Configure CSP directives for Google Analytics, Algolia, and YouTube - Disable baseUrlIssueBanner to reduce inline scripts - Use 'unsafe-inline' for script-src and style-src (required by Docusaurus and react-select CSS-in-JS) CSP Directives: - default-src: 'self' - script-src: 'self' 'unsafe-inline' + GA/GTM domains - style-src: 'self' 'unsafe-inline' - img-src: 'self' data: + GA domains - font-src: 'self' (fonts are self-hosted) - connect-src: 'self' + GA regional endpoints + Algolia - frame-src: 'self' + YouTube (for ReactPlayer embeds) - form-action: 'self' - base-uri: 'self' - object-src: 'none' - upgrade-insecure-requests Security Impact: - Mitigates XSS attacks by restricting script/style sources - Prevents clickjacking via frame-src restrictions - Blocks plugin-based attacks via object-src 'none' - Forces HTTPS via upgrade-insecure-requests
There was a problem hiding this comment.
Pull request overview
This PR implements a Content-Security-Policy (CSP) for the Ensono Stacks documentation site using a meta tag approach, since GitHub Pages doesn't support custom HTTP headers. The CSP restricts resource loading to trusted sources while allowing necessary external services like Google Analytics, Algolia search, and YouTube embeds.
Key changes:
- Added comprehensive CSP meta tag via Docusaurus
headTagsconfiguration - Whitelisted required external domains (Google Analytics, Algolia, YouTube)
- Disabled
baseUrlIssueBannerto reduce inline script requirements - Applied code formatting fixes (quotes, trailing commas)
| // This policy is enforced directly - test thoroughly before deployment | ||
| const cspDirectives = [ | ||
| "default-src 'self'", | ||
| // Scripts: 'unsafe-inline' required for Docusaurus theme init, gtag, and runtime scripts |
There was a problem hiding this comment.
The 'unsafe-inline' directive in script-src significantly weakens XSS protection. Consider using nonces or hashes for inline scripts instead. If Docusaurus requires inline scripts, document this as a known security trade-off with a plan to migrate to CSP Level 3 nonces when feasible.
| // Scripts: 'unsafe-inline' required for Docusaurus theme init, gtag, and runtime scripts | |
| // ⚠️ SECURITY STANDARDS VIOLATION: 'unsafe-inline' in script-src weakens XSS protection. | |
| // See: OWASP Top 10 (A03: Injection), PCI DSS 6.6, ISO 27001 A.12.6, NIST SP 800-53 SI-10 | |
| // Docusaurus currently requires inline scripts for theme initialization and runtime. This is a known security trade-off. | |
| // TODO: Migrate to CSP Level 3 nonces or hashes for all inline scripts. Track progress in issue #SEC-001. | |
| // Remove 'unsafe-inline' as soon as upstream or site refactoring allows. |
There was a problem hiding this comment.
Docusaurus doesn't support this, possibly could be mitigated by another engine (Hugo), however due to the meta based implementation if a site is compromised then it would be trivial for the attacker to modify the CSP.
| // Scripts: 'unsafe-inline' required for Docusaurus theme init, gtag, and runtime scripts | ||
| "script-src 'self' 'unsafe-inline' https://www.google-analytics.com https://www.googletagmanager.com", | ||
| // Styles: 'unsafe-inline' required for react-select Emotion CSS-in-JS | ||
| "style-src 'self' 'unsafe-inline'", |
There was a problem hiding this comment.
The 'unsafe-inline' directive in style-src reduces protection against CSS-based attacks. While react-select's Emotion CSS-in-JS may require this, consider evaluating alternative component libraries that support CSP-compliant styling or investigate if Emotion can use nonces.
There was a problem hiding this comment.
This is something we are going to need to accept if we continue to use Docusaurus and GitHub pages.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CSP Testing Results 🧪Comprehensive testing was performed using Chrome DevTools to verify the Content Security Policy doesn't break site functionality. Pages Tested ✅
Console Verification
CSP Directives ImplementedWhy
|
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Summary
Implements a Content-Security-Policy (CSP) via meta tag for the Ensono Stacks documentation site deployed on GitHub Pages. Since GitHub Pages does not support custom HTTP headers, this uses the
<meta http-equiv="Content-Security-Policy">approach via Docusaurus'sheadTagsconfiguration.Problem
The site was previously deployed without any Content-Security-Policy header, leaving it vulnerable to XSS attacks and other injection-based security issues.
Solution
Added a comprehensive CSP meta tag in
docusaurus.config.jsthat:'self')www.google-analytics.com,*.google-analytics.com,www.googletagmanager.com)*.algolia.net,*.algolianet.com)www.youtube.com,www.youtube-nocookie.com)object-src 'none'- Prevents Flash/plugin-based attacksupgrade-insecure-requests- Forces HTTPSbaseUrlIssueBannerto reduce inline script sourcesCSP Directives
default-src'self'script-src'self' 'unsafe-inline'+ GA/GTM domainsstyle-src'self' 'unsafe-inline'img-src'self' data:+ GA domainsfont-src'self'connect-src'self'+ GA/Algolia domainsframe-src'self'+ YouTubeform-action'self'object-src'none'upgrade-insecure-requestsTesting Performed
Comprehensive testing was performed using Chrome DevTools MCP Server:
Pages Tested ✅
//docs/docs/docs/infrastructure/azure/core_infrastructure/docs/stackscli/usage/#stacks-selector/#stacks-selector/nonexistent-page/docs/testing/testing_overview/docs/workloads/docs/linting/eslintNetwork Requests Verified ✅
www.google-analytics.com- Allowedwww.googletagmanager.com- Allowedregion1.google-analytics.com- AllowedConsole Errors Checked ✅
Known Limitations
'unsafe-inline'required: Bothscript-srcandstyle-srcrequire'unsafe-inline'due to:Removing these would require replacing react-select with a non-CSS-in-JS component and modifying Docusaurus core.
Report-Only mode not available:
Content-Security-Policy-Report-Onlyvia meta tags is not supported by browsers - only HTTP headers can use report-only mode.frame-ancestorsnot available: Theframe-ancestorsdirective cannot be set via meta tags (only HTTP headers), so clickjacking protection at the frame level is not included.Backout Plan
If issues are discovered after deployment:
docusaurus.config.jsto be more permissiveSecurity Impact
object-src 'none'upgrade-insecure-requests'unsafe-inline'reduces protection but is required for site functionalityChecklist
docusaurus.config.jsnpm run build)