Contact Us

Settings

Pendo Help CenterSettingsContent security policy

Content security policy

Overview

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. If you are running into an issue with your CSP, you may need to make an adjustment to allow our product.

This article outlines the minimum required directives to allow Pendo full functionality, as well as compatible guide content examples for applications with strict CSP.

Guide Delivery Settings

For applications with strict CSP, you will want to ensure your Guide Delivery Settings are set to XHR.

To access your Guide Delivery settings, navigate to the Install Settings page, click the Agent Settings tab, then click "Manage Production Settings".

Ensure the XHR radio button is selected.

guideDisplay.png

Minimum Required Directives

note: Replace all occurrences of foo.example.com below with your appropriate hostname. Replace SUB_ID with your Subscription ID obtained by reaching out to help@pendo.io.

You may include https:// before any hostnames if desired.

Minimum required CSP directives for:

Full functionality including the Designer:

script-src foo.example.com 'unsafe-inline' 'unsafe-eval' app.pendo.io pendo-io-static.storage.googleapis.com cdn.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
style-src foo.example.com 'unsafe-inline' app.pendo.io cdn.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
img-src foo.example.com cdn.pendo.io app.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
connect-src app.pendo.io;
frame-ancestors app.pendo.io;

Full agent functionality and displaying guides in production:
This excludes the Designer and any inline guide style or scripts

script-src foo.example.com pendo-io-static.storage.googleapis.com cdn.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
style-src foo.example.com app.pendo.io cdn.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
img-src foo.example.com cdn.pendo.io app.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
connect-src app.pendo.io;
frame-ancestors app.pendo.io;

Displaying guides in staging:

script-src foo.example.com app.pendo.io pendo-io-static.storage.googleapis.com cdn.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
style-src foo.example.com app.pendo.io cdn.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
img-src foo.example.com cdn.pendo.io app.pendo.io pendo-static-SUB_ID.storage.googleapis.com;
connect-src app.pendo.io;
frame-ancestors app.pendo.io;

Compatible Guide Content

While Pendo is compatible with strict CSP directives, it is the user’s responsibility to ensure the guide content is compatible with your CSP restrictions.

If unsafe-inline is not present within the style-src and script-src directives, inline CSS and JavaScript within the HTML tab of the guide will not function correctly. To prevent an unexpected guide experience, all inline styles and scripts should be moved to the CSS and JS tabs of the guide or template.

With properly set minimal CSP directives (no inline directives), you should be able to fully use the Pendo Designer to show and tag your features. The X-Frame-Options plugin should enable you to use the Designer in guide editing mode with strict CSP. It is important to test guide content outside of the designer and with the X-Frame-Options plugin turned off.

Example of Strict CSP Compatible Content

The basic concept is to remove all "unsafe-inline" styling and JavaScript.

For example, all of the inline styling and JavaScript within this HTML button:

<button class="_pendo-guide-next_" style="color:blue;"
onclick="pendo.onGuideAdvanced()">Next</button>

would be distributed across the HTML, CSS, and JS tabs of the guide. The below example illustrates how to break down elements in guide content. You or your team’s developers may have a different or even better approach:

HTML

<button class="_pendo-guide-next_">Next</button>

CSS

#bluebutton { color: blue; }

JavaScript

(function wireGuideAdvanceButton (step) {
    step && step.attachEvent(step.guideElement[0], 'click', function (e) {
        var advanceButton = pendo.dom(e.target || e.srcElement).closest('._pendo-guide-next_');
        if (advanceButton.length) {
            pendo.onGuideAdvanced();
        }
    });
})(step,guide);

Additional Resources

© 2018 Pendo  |  Terms of Service  |  Privacy Policy