From 09ce02dbdfda39b7c4437ce0c719e28eab1176c8 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 1 Feb 2026 18:50:46 +0800 Subject: [PATCH] feat: Add support for CSP3 keyword-sources --- system/HTTP/ContentSecurityPolicy.php | 15 ++++++- .../system/HTTP/ContentSecurityPolicyTest.php | 42 +++++++++++++++++++ user_guide_src/source/changelogs/v4.7.0.rst | 1 + 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index db1db04e0fdf..86089be660fd 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -200,15 +200,28 @@ class ContentSecurityPolicy protected $reportOnly = false; /** - * Set of valid source keywords. + * Set of valid keyword-sources. + * + * @see https://www.w3.org/TR/CSP3/#source-expression * * @var list */ protected $validSources = [ + // CSP2 keywords 'self', 'none', 'unsafe-inline', 'unsafe-eval', + // CSP3 keywords + 'strict-dynamic', + 'unsafe-hashes', + 'report-sample', + 'unsafe-allow-redirects', + 'wasm-unsafe-eval', + 'trusted-types-eval', + 'report-sha256', + 'report-sha384', + 'report-sha512', ]; /** diff --git a/tests/system/HTTP/ContentSecurityPolicyTest.php b/tests/system/HTTP/ContentSecurityPolicyTest.php index e8db11eed9a4..bf12601dd1c6 100644 --- a/tests/system/HTTP/ContentSecurityPolicyTest.php +++ b/tests/system/HTTP/ContentSecurityPolicyTest.php @@ -118,6 +118,48 @@ public function testDefaults(): void $this->assertContains("style-src 'self'", $directives); } + public function testKeywordSourcesAreEnclosedInSingleQuotes(): void + { + // clear directives set by config + $this->csp->clearDirective('child-src'); + $this->csp->clearDirective('form-action'); + $this->csp->clearDirective('img-src'); + $this->csp->clearDirective('object-src'); + $this->csp->clearDirective('script-src'); + $this->csp->clearDirective('style-src'); + + $this->csp->addBaseURI('self'); + $this->csp->addChildSrc('none'); + $this->csp->addFontSrc('unsafe-inline'); + $this->csp->addFormAction('unsafe-eval'); + $this->csp->addFrameAncestor('strict-dynamic'); + $this->csp->addFrameSrc('report-sample'); + $this->csp->addImageSrc('wasm-unsafe-eval'); + $this->csp->addMediaSrc('unsafe-allow-redirects'); + $this->csp->addManifestSrc('trusted-types-eval'); + $this->csp->addObjectSrc('report-sha256'); + $this->csp->addScriptSrc('report-sha384'); + $this->csp->addStyleSrc('report-sha512'); + $this->assertTrue($this->work()); + + $header = $this->getHeaderEmitted('Content-Security-Policy'); + $this->assertIsString($header); + + $directives = $this->getCspDirectives($header); + $this->assertContains("base-uri 'self'", $directives); + $this->assertContains("child-src 'none'", $directives); + $this->assertContains("font-src 'unsafe-inline'", $directives); + $this->assertContains("form-action 'unsafe-eval'", $directives); + $this->assertContains("frame-ancestors 'strict-dynamic'", $directives); + $this->assertContains("frame-src 'report-sample'", $directives); + $this->assertContains("img-src 'wasm-unsafe-eval'", $directives); + $this->assertContains("media-src 'unsafe-allow-redirects'", $directives); + $this->assertContains("manifest-src 'trusted-types-eval'", $directives); + $this->assertContains("object-src 'report-sha256'", $directives); + $this->assertContains("script-src 'report-sha384'", $directives); + $this->assertContains("style-src 'report-sha512'", $directives); + } + #[PreserveGlobalState(false)] #[RunInSeparateProcess] public function testConfigSetsListAsDirectivesValues(): void diff --git a/user_guide_src/source/changelogs/v4.7.0.rst b/user_guide_src/source/changelogs/v4.7.0.rst index 562c7f5a4da9..9d50cf764e6f 100644 --- a/user_guide_src/source/changelogs/v4.7.0.rst +++ b/user_guide_src/source/changelogs/v4.7.0.rst @@ -280,6 +280,7 @@ Libraries - **Cache:** Added support for HTTP status in ``ResponseCache``. - **Cache:** Added ``Config\Cache::$cacheStatusCodes`` to control which HTTP status codes are allowed to be cached by the ``PageCache`` filter. Defaults to ``[]`` (all status codes for backward compatibility). Recommended value: ``[200]`` to only cache successful responses. See :ref:`Setting $cacheStatusCodes ` for details. - **Cache:** Added `APCu `_ caching driver. +- **ContentSecurityPolicy:** Added new CSP3 keyword-sources to support the latest CSP3 specification. - **CURLRequest:** Added ``shareConnection`` config item to change default share connection. - **CURLRequest:** Added ``dns_cache_timeout`` option to change default DNS cache timeout. - **CURLRequest:** Added ``fresh_connect`` options to enable/disable request fresh connection.