Content Security Policy
CKEditor 5 is compatible with applications that use CSP rules and helps developers build a secure web.
The recommended CSP configuration for Cloud deployments that allows the rich-text editor to run out–of–the–box with all standard features using the content like images or media from external hosts looks as follows:
default-src 'none'; connect-src 'self'; script-src 'self' https://cdn.ckeditor.com https://proxy-event.ckeditor.com ; img-src * data:; style-src 'self' 'unsafe-inline'; frame-src *
Copy codeThe recommended CSP configuration for self-hosted deployments (npm/ZIP) that allows the rich-text editor to run out–of–the–box with all standard features using the content like images or media from external hosts looks as follows:
default-src 'none'; connect-src 'self'; script-src 'self'; img-src * data:; style-src 'self' 'unsafe-inline'; frame-src *
Copy codeSome CSP directives have an impact on certain rich-text editor features. Here is the round-up of directives and their specific roles in the editor:
-
default-src 'none': Resets the policy and blocks everything. All successive directives work as a whitelist. By itself, as long as it is followed by other directives, it has no impact on the editor. -
connect-src 'self'- Allows the editor upload features to use
XMLHttpReqests(Ajax) to upload files to the server, for instance, when an image is pasted or dropped into the editor content. The'self’ value ensures the requests remain within the same host. - Allows auto–saving editor data using
XMLHttpRequest.
Note: To use CKEditor Cloud Services, include the
http://*.cke-cs.comdomain in theconnect-srcdirective, for instance:connect-src 'self' http://*.cke-cs.com. - Allows the editor upload features to use
-
script-src 'self': Allows the execution of JavaScript from the current host only and can be applied only if the CKEditor 5 script file (<script src="[ckeditor-build-path]/ckeditor.js"></script>) is also served from that host.Note: If CKEditor 5 is served from Cloud, make sure the value of
script-srcincludes the required hosts, one for the CDN, and one for the license check server:script-src 'self' https://cdn.ckeditor.com https://proxy-event.ckeditor.com. -
img-src * data:- The
*directive value allows images in the editor content to come from any hosts. - The
data:value allows:- Pasting images from the clipboard and from MS Office into the editor content. Pasted images are usually represented as Base64–encoded strings (
<img src="data:..." />) and withoutdata:they cannot be displayed and uploaded. - Displaying the media embed feature placeholders for the inserted media.
- Pasting images from the clipboard and from MS Office into the editor content. Pasted images are usually represented as Base64–encoded strings (
Note: Use the more strict
img-src 'self'if all images in the editor content are hosted from the same domain and you do not want to enable the media embed and paste from Word features. - The
-
style-src 'self' 'unsafe-inline':- The
selfdirective allows to load styles from the site’s own domain. Since v42.0.0, the editor distributes its stylesheets. If you need to load styles from some other domain, add them explicitly:style-src https://trusted-styles.example.com;. - The directive
unsafe-inlineis required to make the styles of certain features work properly. For instance, you are going to need it if you want to enable such editor features as font or text alignment or any other feature that uses the inlinestyle="..."attributes in the content.
Note: Inline styles are also required when using list item marker formatting. For example, if you apply font color, size, or family to list markers, the editor uses inline style attributes to render them. Because of this,
unsafe-inlinemust be allowed for the styles to display correctly. - The
-
frame-src *: Necessary for the media embed feature to load media with previews (containing<iframe>).Note: Use the more strict
frame-src 'self'if all the media in the edited content come from the same domain as your application.
A different set of Content Security Policy directives might be necessary to run CKFinder along with CKEditor 5. Check out the file manager documentation to learn more.
Knowing the role of each directive, the strictest set of rules that allows CKEditor 5 to run is as follows:
default-src 'none'; connect-src 'self'; script-src 'self'; img-src 'self'; style-src 'self'; frame-src 'self'
Copy codeThis comes with some trade–offs, though. For example, it requires you to:
- Load images in the content from the same host.
- Load previewable media in the content from the same host.
- Give up certain features that use inline styles like font or text alignment.
- Give up pasting images from the clipboard or from Office.
Trusted Types is a browser mechanism against DOM-based XSS. It applies to DOM injection sinks: the properties and methods that turn a string into live HTML, such as innerHTML, insertAdjacentHTML() or DOMParser#parseFromString(). It also applies to attributes that run code or load a script, such as onclick or the src attribute of a <script> element. Under Trusted Types, a sink rejects a plain string and accepts only a value produced by a policy that the application allows.
CKEditor 5 supports running in applications that enforce Trusted Types. It creates its own policies and passes through them every value that it writes to a sink or to one of these attributes. Your application needs to allow the names of these policies, together with the policies of any third-party code that your setup includes.
Add two directives to the Content Security Policy that your application sends:
require-trusted-types-for 'script'; trusted-types ckeditor5 ckeditor5-integrations lit-html;
Copy codeThe first directive turns the mechanism on. The second one lists the policy names that the browser allows. Add the names below to any that your application already lists. The ckeditor5 name is always required, and the other two depend on your setup:
ckeditor5– the policy of the editor.ckeditor5-integrations– a policy that theuseCKEditorCloud()andloadCKEditorCloud()helpers create to inject the editor scripts. Add it whenever you load the editor from CDN with these helpers, for example in the React, Vue.js 3+, or Angular integration.lit-html– a policy that the Uploadcare file uploader creates. It does not come from the editor. Add it whenever your build contains that feature. The ready-made premium features bundle always contains it, and the CDN helpers load that bundle when you set theirpremiumoption totrue.
Under enforcement, the editor cannot recover from a refused policy, so it is never created. The console names the policy that was refused. What differs is when the failure happens and which code reports it.
- Without
ckeditor5, the failure happens as soon as the browser loads the editor’s code. The editor also logs thetrusted-types-policy-creation-failedwarning, because it creates that policy itself and catches the refusal. - Without
ckeditor5-integrations, the failure happens before the browser loads the editor’s code. The CDN helpers also fail with theTrustedTypesPolicyCreationErrorerror, because they create that policy themselves. - Without
lit-html, the failure happens as soon as the browser loads the editor’s code. Only the browser reports it, because the editor does not create that policy and never sees the refusal.
A policy is also refused when your application already created one with the same name, even though the name is listed. An application that uses Lit itself can hit this, because the premium features bundle brings its own copy. The same happens to ckeditor5-integrations when the page loads more than one copy of the @ckeditor/ckeditor5-integrations-common package. To allow the same name twice, add 'allow-duplicates' to the trusted-types directive.
The policy of the editor returns every string unchanged. It makes the browser accept the markup and the attribute values that the editor writes, and it does not inspect, clean, or filter anything. Turning Trusted Types on therefore does not make the editor filter content, and the responsibility for the safety of the data loaded into the editor stays with your application, exactly as before.
This matters most for the HTML embed feature. When it is configured to show previews, the browser runs whatever the embedded snippets contain. Trusted Types does not change that, and the config.htmlEmbed.sanitizeHtml option remains the way to control it.
If you configure General HTML Support to allow event handler attributes, such as onclick, or <script> elements, the editor keeps them in the content. The policy passes these values through unchanged, like the HTML. As a result:
- The data that the editor returns contains them, exactly as without Trusted Types.
- Nothing runs while users edit the content, because the editing view renames such attributes and replaces
<script>elements. The only exception is an attribute that your own converter explicitly allows.
To keep such content out of the editor, exclude it with the htmlSupport.disallow option.
To find out whether your application enforces Trusted Types, the editor writes to a sink once and checks whether the browser refuses the value. There is no other reliable way to tell.
The editor catches the refusal, but the browser still logs an error of its own and reports a CSP violation. In Chrome it reads This document requires 'TrustedHTML' assignment, and other browsers word it differently. This happens once per page, the first time the editor runs that check. Nothing is broken by it.
Four cases are affected when your application enforces Trusted Types. All four come from third-party code that writes HTML or attribute values the editor cannot route through its policy.
In the first two cases, the editor turns the feature off and logs a warning instead of letting it fail:
- The color picker, everywhere it appears: font color and font background color and table properties and table cell properties. The color palettes and the document colors are not affected, so users keep every predefined color and lose only the custom ones. The editor logs
color-picker-unavailable-with-trusted-typesonce for every color selector that it creates. To turn the picker off yourself and stop the warning, set thecolorPickeroption of each of those features tofalse. - Parts of the file managers.
- Uploadcare: the dialog that the toolbar button opens and the image editor. Uploading files by pasting or dropping them keeps working. The editor logs
uploadcare-unavailable-with-trusted-typesonce while it starts. - CKBox: the image editor. Choosing assets keeps working. The editor disables its Edit image button and logs
ckbox-image-edit-unavailable-with-trusted-typesonce while it starts. The Edit button in the CKBox dialog is part of CKBox, so the editor cannot disable it: it opens the image editor, but the image never loads. When CKBox shows the thumbnail of a PDF file, the browser also reports a refusedWorker. The thumbnail still renders.
- Uploadcare: the dialog that the toolbar button opens and the image editor. Uploading files by pasting or dropping them keeps working. The editor logs
The last two cases are different because they are errors on content rather than a feature switched off:
- Markdown that contains a named character reference, such as
or&. Parsing such content fails, while Markdown without character references works. This affects every feature that parses Markdown, not only Markdown output. - Markdown with HTML that contains event handlers, external scripts, or inline frame content, such as
<p onclick="...">,<script src="...">, or<iframe srcdoc="...">. Parsing such content fails, while Markdown without them works. This affects Markdown output and pasting Markdown.
To keep your own plugins and UI working under Trusted Types, pass the HTML they write to the DOM through the trustedHtml() helper, which is safe to call in any browser:
import { trustedHtml } from 'ckeditor5';
element.innerHTML = trustedHtml( '<p>Hello world!</p>' );Copy codetrustedHtml() marks as trusted whatever it receives, and it checks nothing. Use it only for markup that your own code produced. Never pass it content that comes from a user, from a server response, or from any other outside source. Sanitize such content first.