CSP Enforcement blocks SPFx script even its CDN URL has been imported from the App Catalog
Target SharePoint environment
SharePoint Online
What SharePoint development model, framework, SDK or API is this about?
other (enter in the "Additional environment details" area below)
Developer environment
None
What browser(s) / client(s) have you tested
- [ ] 💥 Internet Explorer
- [ ] 💥 Microsoft Edge
- [x] 💥 Google Chrome
- [ ] 💥 FireFox
- [ ] 💥 Safari
- [ ] mobile (iOS/iPadOS)
- [ ] mobile (Android)
- [ ] not applicable
- [ ] other (enter in the "Additional environment details" area below)
Additional environment details
SharePoint Admin Center
Describe the bug / error
Microsoft recently introduced Content Security Policy (CSP) enforcement in SharePoint Online, and the new Trusted Script Sources configuration is now available in the admin center.
On my tenant, all my SPFx solution deployments automatically add their CDN script URLs into Trusted Script Sources as expected.
However, when navigating to any page containing my SPFx web parts and adding the query string ?csp=enforce, SharePoint still blocks the script, even though the exact CDN URL appears in the list of trusted sources and is marked as Imported from app catalog.
In the browser console, I receive this error (domain and webpart anonymized + well formated):
Loading the script 'https://cdn.{my-domain}.net/webparts/prd/2025.11.25.64207/{my-webpart}_0c261bde6389a7ca3ea2.js' violates the following Content Security Policy directive: "script-src 'unsafe-eval'
https://cdn.{my-domain}.net/webparts/prd/2025.6.4.55003
https://cdn.{my-domain}.net/webparts/prd/2025.6.18.55826
https://cdn.{my-domain}.net/webparts/prd/2025.6.20.55920
https://cdn.{my-domain}.net/webparts/prd/2025.7.16.57858
https://cdn.{my-domain}.net/webparts/prd/2025.7.21.58232
https://cdn.{my-domain}.net/webparts/prd/2025.8.8.59141
https://cdn.{my-domain}.net/webparts/prd/2025.8.11.59281
https://cdn.{my-domain}.net/webparts/prd/2025.8.13.59486
https://cdn.{my-domain}.net/webparts/prd/2025.9.10.61049
https://cdn.{my-domain}.net/webparts/prd/2025.9.11.61069
https://cdn.{my-domain}.net/webparts/prd/2025.9.11.61102
https://cdn.{my-domain}.net/webparts/prd/2025.9.16.61451
https://cdn.{my-domain}.net/webparts/prd/2025.9.19.61762
https://cdn.{my-domain}.net/webparts/prd/2025.9.24.62135
https://cdn.{my-domain}.net/webparts/prd/2025.10.7.62692
https://cdn.{my-domain}.net/webparts/prd/2025.10.8.62741
https://cdn.{my-domain}.net/webparts/prd/2025.10.14.63049
https://cdn.{my-domain}.net/webparts/prd/2025.10.20.63172
https://cdn.{my-domain}.net/webparts/prd/2025.10.23.63294
https://cdn.{my-domain}.net/webparts/prd/2025.10.30.63595
https://cdn.{my-domain}.net/webparts/prd/2025.11.5.63741
https://cdn.{my-domain}.net/webparts/prd/2025.11.18.63986
https://cdn.{my-domain}.net/webparts/prd/2025.11.25.64207 <===== CDN URL automatically imported into Trusted Script Sources
https://contentstorage.osi.office.net
https://swx.cdn.skype.com
https://res.delve.office.com
https://lpcres.delve.office.com
https://widget.uservoice.com
https://by2.uservoice.com
https://www.bing.com/api/maps
https://www.bing.com/rms
https://fabriciss.azureedge.net
https://ajax.aspnetcdn.com
https://js.monitor.azure.com
https://r4.res.office365.com
https://public-cdn.sharepointonline.com
https://teams.microsoft.com
*.cdn.office.net
*.fluidpreview.office.net
*.onecdn.static.microsoft
https://webshell.suite.office.com
https://amcdn.msftauth.net
https://res-1.cdn.office.net
https://res-1.public.onecdn.static.microsoft
*.bing.com
c64.assets-yammer.com
*.virtualearth.net
*.ditu.live.com
appsforoffice.microsoft.com
platform.twitter.com
https://login.microsoftonline.com
https://publiccdn.sharepointonline.com
https://public-cdn-staging.sharepointonline.com
https://loki.delve.office.com
https://res.cdn.office.net/midgard/
https://substrate.office.com
https://res.public.onecdn.static.microsoft
https://c1-word-view-15.cdn.office.net
'self'
alcdn.msauth.net
https://res-2.public.onecdn.static.microsoft
https://res-3.cdn.office.net
https://shell.cdn.office.net
https://res.cdn.office.net
'nonce-y188x3lm66'
'sha256-ATReICQsd+smV/PvrA4eH+DuxsenS4SxbGcSjySJlBA='
'sha256-2vr5KMButMK7a+bOf/ned/cPnF2yNooMulXA8E65wGw='
'sha256-Ie4uWHgjrKA4WjOrgfxpFEHOCYe/wqVItoHI+ySGTd4='".
Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
The action has been blocked.
The CSP violation explicitly lists the correct versioned folder (2025.11.25.64207), confirming that SharePoint knows the source is trusted — but still blocks the script.
The result is that SPFx components fail to load when CSP is enforced, even though the tenant configuration is correct.
This seems to indicate either:
- a CSP evaluation bug,
- or a mismatch between how SharePoint imports trusted sources from the App Catalog and how the CSP engine evaluates them at runtime.
Steps to reproduce
- Deploy an SPFx solution to the App Catalog using a CDN hosted script (e.g.
https://cdn.domain.net/webparts/prd/<version>/). - Verify in SharePoint Admin Center → Content Security Policy → Trusted Script Sources that the CDN URL is automatically added with status Imported from app catalog.
- Add the SPFx web part to a modern page.
- Load the page using the query parameter:
?csp=enforce - Open the browser console.
Actual result:
A CSP error appears, indicating that the script violates the script-src directive — even though the CDN URL is listed in Trusted Script Sources.
Expected behavior
When a script URL is present in Trusted Script Sources (automatically imported from the App Catalog), SharePoint should allow the script to load during CSP enforcement. The SPFx web part should load normally without CSP violations.
Is https://cdn.{my-domain}.net/webparts/prd/2025.11.25.64207 your actual script name? I ran into issues where a missing appended forward slash was required
@jbolliet-mozzaik365 : can you try with explicitly adding https://cdn.{my-domain}.net/webparts/prd/2025.11.25.64207/{my-webpart}_0c261bde6389a7ca3ea2.js as trusted source and see if that works? Also, I've noticed that sometimes you need to reload (CTRL-R) the browser session a few times before changes are picked up.
If it helps, I've had a similar problem since Monday evening (GMT). It happens with web parts that are in the site collection's application catalog.
It also happens with files stored on the Microsoft CDN (https://public-cdn.sharepointonline.com/).
On my tenant, the tenant's application catalog doesn't seem to be affected, just the site collection app catalog. I have no solution (clearing the cache doesn't change anything).
It happened suddenly, without any changes (no wbepart deployments on my end).
Error :
Access to fetch at 'https://public-cdn.sharepointonline.com/***/sites/***/ClientSideAssets/9ed633b7-0cad-49eb-836b-ca786a9f18f0/***_50753639c3edee2f4f99.js' from origin 'https://***.sharepoint.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
@jansenbe , @MortenGuldbaek , Thank you for your suggestions! I can confirm that adding a trailing slash to the URL auto-imported by SharePoint, from the package deployed in the App Catalog, removes the issues we were seeing. This clearly indicates a bug, as these automatically generated URLs should work out of the box without requiring manual adjustments. Note that this behavior does not occur on all tenants, which is rather surprising.
Our findings show that we are having to suffix the cdnBasePath (in /config/write-manifests.json) with a trailing slash to ensure it is not handled as a single script, but rather a directory allowed to load multiple scripts.
Doing this ensures that our extensions and webparts are loaded correctly when forcing CSP compliance (?csp=enforce).
However, for some reason, the new cdnBasePath is still reported by SharePoint as a CSP violation, even though the script loads and the extension runs.
In the attached screenshot, the green redacted bar represents our CDN URL ending with the trailing slash /
@jansenbe can you comment on if this is overzealous reporting or if we will indeed be limited if using a trailing slash approach?
(Private domains redacted)
@MortenGuldbaek : can you share the url in trusted sources and your actual script url here. Please put contoso as your tenant name and pick a fake product/script name to ensure your data in anonymous
@jansenbe certainly, here you go:
Note: CDN is hosted on Azure, not SharePoint. Host, sub-domain, and path have been anonymized.
Trusted script sources record https://mycdnonazure.contoso.com/assets/99999/
Actual extension script (one of many) loaded in SharePoint https://mycdnonazure.contoso.com/assets/99999/ex-tension_a91b2e6c3d4f5g6h7i8.js
URL reported as blocked violation in console (matches the Base Path) https://mycdnonazure.contoso.com/assets/99999/
@MortenGuldbaek : I assume you've done a few CTRL-R's to fully refresh the page. Just to confirm CSP is working: when you add https://mycdnonazure.contoso.com (no trailing slash) the scripts are loaded?
@MortenGuldbaek : do you see the same behavior when you test on regular page versus a list page?
@jansenbe
CTRL+R Yes we have done several CTRL+R in all of the below experiences, all with the "?csp=enforce" query parameter 👍
SitePage vs. List vs. Library experiences We only see the invalid reporting on Document Libraries and List Views right now, on a regular page they are not shown.
Removing trailing slash from Trusted script source entry If I change my Trusted script source to be without the trailing slash "/", then my extension is blocked and will not load in any of above experiences. ❌
Doing this also logs the blocked script as the specific script, not the base path: https://mycdnonazure.contoso.com/assets/99999/ex-tension_a91b2e6c3d4f5g6h7i8.js
We are experiencing a similar issue. If the cdnBasePath in the write-manifest.json file includes a path (not just the domain) and that path does not end with a trailing slash (/), the CSP (Content Security Policy) enforcement will block all scripts. Why does this happen? When the solution is deployed, the value of cdnBasePath is automatically added to the Trusted Script Sources. CSP rules require that if a source contains a path (beyond the domain), it must end with a slash. Without the slash, the CSP validation fails, and scripts are blocked. The problem: Currently, cdnBasePath allows configuration without a trailing slash, and SPFx components work fine in this setup. This means there are likely many SPFx apps already published in stores and deployed in customer tenants that will stop working after March 1, 2026, when stricter CSP enforcement begins.
Can someone from Microsoft confirm whether this issue is known and if there will be a fix or guidance provided before March 1, 2026?
@MortenGuldbaek : just to ensure we're on the same page here. When you use https://mycdnonazure.contoso.com/assets/99999/ (with trailing slash) then when your SPFx solution tries to load https://mycdnonazure.contoso.com/assets/99999/ex-tension_a91b2e6c3d4f5g6h7i8.js:
- On regular pages you see no warnings in report mode, no errors in enforce mode?
- On list/library pages you see warnings in report mode and errors in enforce mode?
When checking this please verify that https://mycdnonazure.contoso.com/assets/99999/ is included in the error/warning message.
@florianwachter : you still see the cdnBasePath getting added to trusted sources without trailing slash? What you see is correct behavior, only root domains without a trailing slash allow all scripts under that domain to be loaded. If there's a path and you need scripts inside that path the trailing slash is required.
@jansenbe : Yes, I still see it added without a slash. I just tested it again. I also believe that this is not the solution to the problem, since this would mean that apps have to be re-deployed in every tenant. I think the solution should be to add all the Trusted Script Sources to the CSP with a trailing slash (except files and domains). What do you think?
@florianwachter : we'll fix the process that adds trusted sources when the app is added the tenant app catalog and append the slash if not present. For already added solutions you'll need to manually append the slash to the trusted script sources.
@jansenbe : Thank you for your response. If I understand correctly, this means we’ll need to reach out to the SharePoint administrators of hundreds of customers and inform them that they must manually update the trusted script sources to continue using our apps after March 1. As you can imagine, this is extremely challenging for us and, even more so, for our customers. I suspect there are many other apps affected that may not yet be aware of this upcoming change.
@jansenbe these are my findings:
Trusted Script Resource value: https://mycdnonazure.contoso.com/assets/99999/ (Trailing slash included)
Testing Context:
?csp=enforce Regular Pages:
- Console: Clean (No errors/warnings) ✅
- Script Execution: Success ✅
List/Library Pages:
- Console: Error ❌ (Reported specifically as https://mycdnonazure.contoso.com/assets/99999/)
- Script Execution: Success ✅ Weird part is that it says https://mycdnonazure.contoso.com/assets/99999/ is blocked, but the execution of https://mycdnonazure.contoso.com/assets/99999/ex-tension_a91b2e6c3d4f5g6h7i8.js ran fine
?csp=report Regular Pages:
- Console: Clean ✅
- Script Execution: Success ✅
List/Library Pages:
- Console: Warning ❌ (Reported specifically as https://mycdnonazure.contoso.com/assets/99999/)
- Script Execution: Success ✅
Regarding the proposed Solution I appreciate the notion that new solutions added will have the forward slash appended, meaning that we do not have to inject the slash from our side.
However, I share @florianwachter concern that existing provisioned packages will stop working is problematic.
If the Trusted Script Resources entries were already created based on already deployed SPFx solution packages, then surely it can be done again.
@florianwachter / @MortenGuldbaek : fair feedback on the re-run of the trusted sources population. I'll see what's possible and report back on this in January.