Content Security Policy#

If your site has a Content Security Policy, it needs a few sources for the Neo SDK. With the script-tag embed, the chat, document search, and the document view run under a strict policy, with no 'unsafe-inline', no 'unsafe-eval', and no source but your own site and your proxy. Only the PDF viewer needs more. The React components need a few sources of their own, listed in the React Components section.

For setting up the proxy and the page, see the Embedding Neo Chat in Your Own App or Site page.

Directives#

For the Chat#

These directives apply to the whole chat, including document search and the document view. <proxy> is the origin of your proxy, or 'self' if the proxy is on the origin of the page.

Directive

Sources

Needed for

Without it

script-src

Wherever you host neo-sdk.js: 'self' on your own site, or the CDN host.

The script of the chat.

Nothing loads.

connect-src

<proxy>

Every request that the chat makes: sign-in, answers, conversations, search, and documents.

The chat cannot load or answer.

img-src

The hosts that you let documents show images from.

Thumbnails, and images in the text of a document at an absolute address.

That image is blocked. A thumbnail falls back to a file-type icon.

img-src

blob:

Thumbnails and images in the text of a document that your Squirro instance stores, which the widgets fetch through your proxy. Previews of images that a reader attaches, if uploads are on.

A stored thumbnail falls back to a file-type icon, a stored image in a document is blocked, and an attached image has no preview.

The chat needs nothing in style-src or font-src. It applies its styles in a way that the policy does not govern, adds no inline styles, and uses the fonts of your page.

Warning

Limit img-src to hosts that you trust, and do not open it to https: or *. An answer can name an image at any address that the agent writes, including one that a document planted in your project asked for, and loading it would send a request to that host. The widget shows an answer image only when it comes from the origin of your page, and shows any other image as its alt text, without requesting it.

For the PDF Viewer#

These directives apply only if you show PDF documents. <proxy> is the origin that pdfViewer.assetsUrl points at, which is your proxy by default, since the viewer loads its files from there.

Directive

Sources

Needed for

Without it

script-src

<proxy> 'wasm-unsafe-eval'

The script of the viewer, and compiling its engine.

No page renders.

worker-src

blob:

The engine of the viewer, which runs in a background worker.

No page renders.

connect-src

<proxy>

The downloads of the viewer, from the same source as its script.

No page renders.

style-src

<proxy> 'unsafe-inline'

The stylesheet of the viewer and its inline styles.

Without <proxy>, no page renders. Without 'unsafe-inline', pages lose some styling.

img-src

blob: data:

Rendered pages, and one image of the viewer.

Without blob:, no page renders.

font-src

<proxy>

The signature fonts of the viewer.

Pages render without them.

Sample Policies#

Merge these policies with what the rest of your site needs. frame-ancestors only works when the policy is sent as a response header, not in a <meta> tag.

Proxy on the Origin of Your Page#

If your proxy is on the origin of your site, with base-url="/api/chat", this policy is enough:

default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'self'; img-src 'self' blob:; font-src 'self'; base-uri 'none'; frame-ancestors 'none'

With the PDF viewer:

default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src blob:; style-src 'self' 'unsafe-inline'; connect-src 'self'; img-src 'self' blob: data:; font-src 'self'; base-uri 'none'; frame-ancestors 'none'

Proxy on Another Origin#

If your proxy is on another origin, here https://chat-proxy.example.com, and neo-sdk.js is on your own site:

default-src 'none'; script-src 'self'; style-src 'self'; connect-src https://chat-proxy.example.com; img-src 'self' blob:; font-src 'self'; base-uri 'none'; frame-ancestors 'none'

With the PDF viewer:

default-src 'none'; script-src 'self' https://chat-proxy.example.com 'wasm-unsafe-eval'; worker-src blob:; style-src 'self' https://chat-proxy.example.com 'unsafe-inline'; connect-src https://chat-proxy.example.com; img-src 'self' blob: data:; font-src 'self' https://chat-proxy.example.com; base-uri 'none'; frame-ancestors 'none'

In the policies without the viewer, 'self' in style-src, img-src, and font-src is for the files of your own page, and the chat adds nothing there. In the policies with the viewer, a 'self' that is also the origin of your proxy, as in the same-origin setup, admits the stylesheet and fonts of the viewer too. Keep it in style-src and font-src, even if your page has neither.

What Else to Know#

  • The JSON theme inside <neo-chat>, in a <script type="application/json"> element, is data and needs no source. The inline <script> blocks in the examples of this guide do need one. Move that code into a file of your own, or give the block the nonce of your policy.

  • You do not need 'unsafe-eval'. The viewer checks for it as it starts and works without it, which shows up as one harmless eval report in the console.

  • You do not need the Nutrient metrics host in connect-src either. Leaving it out blocks the metrics call that the viewer makes without a license key, and the browser reports that too.

  • Chromium reports each inline style attribute and <style> element in the HTML of a document that a reader opens, one report per occurrence, so an email or a web page can raise hundreds of reports. Nothing is blocked, and the document shows no inline style.

  • Trusted Types, with require-trusted-types-for 'script', is not supported. Answers and search work, but the browser refuses to open a document whose text is HTML, an answer that contains a character reference such as &amp;, and the PDF viewer.

React Components#

The policies on this page apply to the script-tag embed. With the React components, your own build includes the libraries of the chat unchanged, and a strict policy then also needs the following:

  • A nonce for styles, which you pass to setNonce from the get-nonce package.

  • 'sha256-441zG27rExd4/il+NvIqyL8zFx5XmyNQtE381kSkUJk=' in style-src, for the inline style of the select menus. The hash belongs to the version of the select menu library that the SDK installs. If the browser still reports the select menus, use the hash that it names in the console.

  • worker-src blob:, to export large tables to Excel.

Instead of the nonce and the hash, you can add 'unsafe-inline' to style-src. For details, see the docs/content-security-policy.md file in the package.