SaaS CMS has officially launched! Learn more now.

CSP problems with inline AI script and Episerver QuickNavigator



We have implemented Content Security Policy for our site and boy what a cumbersome process. We have created a middleware that whitelists third party scripts and for inline-scripts we use nonce. But, Application Insights is injected inline and i cant add a nonce to that script and hence it will be blocked. 

Is there a way I can insert the AI script my self with a nonce valuje  instead of magically retrieving it from DXP?

Also, for the Episerver QuickNavigator addon, can i somehow find and add a nonce to this as well without using unsafe-inline which defeats the entire purpose of CSP. 

I've been struggling together with Github Copilot for a while now, not finding a solution. 

May 23, 2024 13:13

Not sure how he's dealt with those issues, but maybe check out Mark Stott's Stott.Security.Optimizely add-on for inspiration? 

May 23, 2024 19:04
EJ - May 26, 2024 18:15
Hey Daniel, thanks. I looked at Stott.Security addon and I really loved it. It was a great and easy to add policies on the fly as the failed and so on.
Although, it did not give me enough freedom to customize the policies as I wanted them, so I ended up creating my own custom middleware. Inspired by Mark Stott.

But, in my project, I use services.AddApplicationInsightsTelemetry(); in the Startup.cs. And this, I think, inserts the AI-script tag into my html leaving me no control over it.

I wish you well on your CSP journey :D

We 'catch' the output of the code that injects scripts and replace-in the nonce. 
So for the navigator we have this in our _Layout.cshtml:

    var optiNav = (await Html.RenderEPiServerQuickNavigatorAsync()).InsertNonce();

And similarly we apply this to the header output of IClientResourceService to inject it for the AI script.

The InsertNonce method is a custom helper method that injects the nonce generated by the Jhoose security addon:

private static readonly Injected<ICspProvider> _cspProvider;

public static string InsertNonce(this IHtmlContent content)
    var nonceValue = _cspProvider.Service.GenerateNonce();

    var htmlString = GetHtmlString(content); // get raw html from IHtmlContent

    var result = htmlString
        .Replace(" nonce ", " ")
        .Replace(" nonce>", " >")
        .Replace("<script ", $"<script nonce=\"{nonceValue}\" ")
        .Replace("<script>", $"<script nonce=\"{nonceValue}\">");

    return result;

Open to a less awkward way of doing this. 

May 24, 2024 1:28
EJ - May 26, 2024 18:22
Hey Arjan, Haha, thanks! :)
So for it's been a semi-long and ardous journey.

Anyway, That looks like a nice way to solve the QuickNavigator-problem. Given our lack of control over the quicknavigator, i think this is a nice solution. I will try it tomorrow and give you an update.

Not sure how you solved the AI-scripts though. In our Optimizely solution, I think this is implemented in our startup.cs.
We use:
- services.AddApplicationInsightsTelemetry();
- services.AddCustomApplicationInsights();
Where that last one is a custom filtering applied to application insights. I do believe the AddApplicationInsightsTelemetry is the one responsible for adding the ai-script-tag into our html.
Arjan Paauw - May 27, 2024 0:45
AI is 'solved' in the same way, so in the header we have:

BTW if that custom AI filtering is from my blog
you should not have that first statement, it'll cause the second to be partially ignored as it also instantiates AI telemetry.
EJ - May 27, 2024 9:52
Thank you, Arjan! Yes, indeed, I looked at your blogpost for inspiration. I only use the AddApplicationInsightsTelemetry() once, i double checked :)
I confirmed that the QuickNavigator is working with correct nonce now. Thank you :) :)

So, a curious thing happens when I add my version of @Html.Raw(ClientResources.RenderAllRequiredResources("Header").InsertNonce()). It adds the script of the Application insights with the correct nonce, but it still injects a duplicate ai-script without the nonce which of course is rejected by my policy. What is going on :p
Is the order of placement of the "RenderAllRequiredResources" within the header-tag of importance, do you know?
Arjan Paauw - May 28, 2024 0:01
That's odd, maybe something somewhere is calling the RenderAllRequiredResources again?
EJ - Jun 03, 2024 5:45
Hi Arjan,
It turns out you are exactly right. I had a duplicate of RenderAllRequiredResources, sort of.
What fixed my issue in the end was a duplicate implementation of @Html.Raw(ClientResources.RenderAllRequiredResources("Header") that I didnt noticed because it was written slightly different: Html.RequiredClientResources(RenderingTags.Header). Removed that, and voilà, it worked as expected. Thanks again for your help :)
Will mark your answer as the correct one.
Arjan Paauw - Jun 03, 2024 5:51
Oh great you figured it out, these things can take so much time!

If you add CSP,  you need to make sure to also enable it for client/template resources 

Edited, May 28, 2024 9:10

Hey EJ,

maybe it's not relevant but it doesn't harm to mention:
- do know that AppInsights could be added already through EPiServer.CloudPlatform.Cms -> AddCmsCloudPlatformSupport(), probably in your startup.cs
- there are scenarios where the app insights script is injected automatically. Mainly CMS 11 where it is controlled through the env variable APPINSIGHTS_JAVASCRIPT_ENABLED)

More info:

We needed to disable auto-injection (through opti support) as it injected the script in some static HTML files which broke some blazor web assembly functionality.


May 31, 2024 13:12
EJ - Jun 03, 2024 5:42
Hi Bob,
Thanks. I went down this path as well and can confirm that this actually worked as well for CMS 12. Support told me that they could disable APPINSIGHTS_CLIENTRESOURCE_ENABLED = False
And then I could insert the AppInsights script where I wanted. So this is a valid way of doing this. Thanks :)

What fixed my issue in the end was a duplicate implementation of @Html.Raw(ClientResources.RenderAllRequiredResources("Header") that I didnt noticed (Html.RequiredClientResources(RenderingTags.Header)).
- Jun 03, 2024 7:37
Hey, thanks for the update!
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.