softcode / module-csp-whitelist
Manage Magento 2 Content Security Policy whitelist hosts from the admin.
Package info
github.com/DritonCa/softcode-magento2-csp-whitelist
Type:magento2-module
pkg:composer/softcode/module-csp-whitelist
Requires
- php: ~8.1.0||~8.2.0||~8.3.0||~8.4.0
- magento/framework: >=103.0.6
- magento/module-backend: >=102.0
- magento/module-config: >=101.2
- magento/module-csp: >=100.4
Requires (Dev)
- phpunit/phpunit: ^9.6
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Manage Magento 2's Content Security Policy (CSP) whitelist from the admin.
Magento 2.4 ships with CSP in report-only mode and expects extra allowed hosts to
be declared in each module's csp_whitelist.xml. That means a developer and a
deploy for every new third-party host. This module lets a store admin add allowed
hosts per directive (script-src, style-src, img-src, …) directly under
Stores → Configuration, and merges them into the collected policy at runtime.
Requirements
| Supported | |
|---|---|
| Magento Open Source / Adobe Commerce | 2.4.6 – 2.4.8 |
| PHP | 8.1 – 8.4 |
Tested by installation, setup:upgrade and setup:di:compile on Magento 2.4.6-p3 with
PHP 8.2; 2.4.7 and 2.4.8 are covered by the Composer constraints but not yet verified
on a live shop.
Installation
composer require softcode/module-csp-whitelist:^2.0 bin/magento module:enable Softcode_CspWhitelist bin/magento setup:upgrade bin/magento setup:di:compile bin/magento cache:flush
Configuration
Stores → Configuration → Softcode → CSP Whitelist:
- Enable the feature.
- Add rows of directive (e.g.
script-src) + host (e.g.*.google.com). The grid starts empty — the module never seeds hosts on your behalf, so you only ever allow what you explicitly add.
Every host is validated and canonicalised when you save. An entry that is not a
safe host-source (a bare *, a data:/javascript: scheme, a keyword like
'unsafe-inline', a path, or a malformed host) aborts the save with a message
naming the offending value — see Security & validation.
How it works
flowchart LR
A["Admin config<br/>(directive + host rows)"] --> H["Helper\\Data<br/>parse + group by directive"]
C["Magento CSP collector"] -->|afterCollect plugin| M["merged policies"]
H --> M
M --> B["CSP header sent to the browser"]
Loading
Plugin\Csp::afterCollect runs after Magento collects the default whitelist. When
the feature is enabled it reads the admin rows via Helper\Data, groups the hosts
by directive, and appends a FetchPolicy for each — so nothing overrides the
built-in policy, it only adds to it.
Security & validation
Because a CSP whitelist is a browser-security control, input is validated on save
by Config\Backend\ArraySerialized, which delegates to Model\HostValidator:
- Accepted:
[scheme://] host [:port]where the scheme (optional) ishttpsorwss, and the host is a domain — optionally with a single leading*.wildcard label (*.example.com) — orlocalhost. - Rejected, with a reason: a bare
*, a wildcard on a bare TLD (*.com) or anywhere but the leading label, insecure (http:/ws:) and other schemes (data:,javascript:,ftp:…), keyword sources ('self','unsafe-inline', nonces, hashes), paths/queries, and malformed hosts. Only the seven directives in the dropdown are allowed. - Hosts are canonicalised (trimmed, lower-cased, trailing
/removed) and deduplicated per directive — on save and again when the policy is built.
Access to the configuration section is guarded by the ACL resource
Softcode_CspWhitelist::config (etc/acl.xml). See SECURITY.md for
the full threat model and the accept/reject table.
Testing
The unit tests are pure logic and run without a Magento install — a small
Test/bootstrap.php autoloads the module and stubs the few Magento contracts the
tests mock (skipped automatically inside a real Magento install):
phpunit -c phpunit.xml.dist
HostValidatorTest— the accept/reject/canonicalise rules and per-directive deduplication (the security core).DataTest— invalid/empty JSON returning no hosts, grouping by directive, skipping incomplete rows, and read-side deduplication.
What CI checks
GitHub Actions runs on every push/PR and fails the build on:
- PHP syntax errors and Magento 2 coding-standard errors (
phpcs --standard=Magento2 -n). - Unit-test failures —
phpunit -c phpunit.xml.distruns the suite above on every push, as a real gate.
Known limitations
- Wildcards are restricted to a single leading label (
*.example.com), but the validator does not consult the Public Suffix List, so*.example.co.ukis accepted. Grant admin access only to trusted roles. - Hosts are appended to the collected policy; the module does not remove hosts that Magento or other modules already whitelist.
Need help?
Installation or adaptation to your shop: SoftCode – Magento 2 development in Copenhagen.
License
MIT — see LICENSE.