Skip to content

Commit

Permalink
🦺 [open-formulieren/security-issues#36] Sanitizing HTML in component …
Browse files Browse the repository at this point in the history
…data

Added a simplistic sanitize function that sanitizes component data when saving the component. This function removes most HTML content from the label, tooltip, description and placeholder component data. Only basic semantic tags (`a`, `b`, `em`, `i`, `string`, `u`) are allowed. Also the allowed attributes has been limited to `href` on `a` tags.
  • Loading branch information
robinmolen committed Mar 5, 2025
1 parent 8df0566 commit 5ca577a
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 12 deletions.
46 changes: 40 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"copy-to-clipboard": "^3.3.1",
"design-token-editor": "^0.6.0",
"django-cookie-consent": "^0.6.0",
"dompurify": "^3.2.4",
"feelin": "^3.1.0",
"flatpickr": "^4.6.9",
"formik": "^2.2.9",
Expand Down
26 changes: 20 additions & 6 deletions src/openforms/js/components/formio_builder/WebformBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import isEmpty from 'lodash/isEmpty';
import React from 'react';
import {createRoot} from 'react-dom/client';
import {IntlProvider} from 'react-intl';
import sanitizeHtml from 'sanitize-html';

import {getIntlProviderProps} from 'components/admin/i18n';
import {getAvailableAuthPlugins} from 'components/form/cosign';
import {getAvailableDocumentTypes} from 'components/form/file';
import {getComponentEmptyValue} from 'components/utils';
import jsonScriptToVar from 'utils/json-script';
import {sanitizeHTML} from 'utils/sanitize';
import {currentTheme} from 'utils/theme';

import {
Expand Down Expand Up @@ -207,6 +209,22 @@ class WebformBuilder extends WebformBuilderFormio {
})();
}

sanitizeComponentData(componentData) {
['label', 'tooltip', 'description'].forEach(property => {
if (!componentData[property]) return;
componentData[property] = sanitizeHTML(componentData[property]);
});

// not-so-elegant input sanitation that formio does... FIXME: can't we just escape
// this with \" instead?
['label', 'tooltip', 'placeholder'].forEach(property => {
if (!componentData[property]) return;
componentData[property] = componentData[property].replace(/"/g, "'");
});

return componentData;
}

/**
* saveComponent method when triggered from React events/formio builder.
*
Expand All @@ -229,13 +247,9 @@ class WebformBuilder extends WebformBuilderFormio {
return NativePromise.resolve();
}

// not-so-elegant input sanitation that formio does... FIXME: can't we just escape
// this with \" instead?
if (componentData) {
['label', 'tooltip', 'placeholder'].forEach(property => {
if (!componentData[property]) return;
componentData[property] = componentData[property].replace(/"/g, "'");
});
// Perform some basic component data sanitizing
componentData = this.sanitizeComponentData(componentData);
}

// look up the component instance with the parent
Expand Down
35 changes: 35 additions & 0 deletions src/openforms/js/utils/sanitize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import DOMPurify from 'dompurify';

const ALLOWED_HTML_TAGS = [
// Basic text tags
'a',
'b',
'br',
'em',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'i',
'p',
's',
'strong',
'sup',
'u',
// Lists
'li',
'ol',
'ul',
];

const ALLOWED_HTML_ATTRIBUTES = ['href', 'target', 'rel'];

export const sanitizeHTML = data => {
return DOMPurify.sanitize(data, {
ALLOWED_TAGS: ALLOWED_HTML_TAGS,
ALLOWED_ATTR: ALLOWED_HTML_ATTRIBUTES,
ALLOW_DATA_ATTR: true,
});
};

0 comments on commit 5ca577a

Please sign in to comment.