logo

CVE-2023-25572 ra-ui-materialui

Package

Manager: npm
Name: ra-ui-materialui
Vulnerable Version: >=4.0.0 <4.7.6 || >=0 <3.19.12

Severity

Level: Medium

CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N

CVSS v4.0: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

EPSS: 0.00914 pctl0.74935

Details

Cross-Site-Scripting attack on `<RichTextField>` ### Impact All React applications built with react-admin and using the `<RichTextField>` are affected. `<RichTextField>` outputs the field value using `dangerouslySetInnerHTML` without client-side sanitization. If the data isn't sanitized server-side, this opens a possible Cross-Site-Scripting (XSS) attack. Proof of concept: ```jsx import { RichTextField } from 'react-admin'; const record = { id: 1, body: ` <p> <strong>War and Peace</strong> is a novel by the Russian author <a href="https://en.wikipedia.org/wiki/Leo_Tolstoy" onclick="document.getElementById('stolendata').value='credentials';">Leo Tolstoy</a>, published serially, then in its entirety in 1869. </p> <p onmouseover="document.getElementById('stolendata').value='credentials';"> It is regarded as one of Tolstoy's finest literary achievements and remains a classic of world literature. </p> <img src="x" onerror="document.getElementById('stolendata').value='credentials';" /> `, }; const VulnerableRichTextField = () => ( <> <RichTextField record={record} source="body" /> <hr /> <h4>Stolen data:</h4> <input id="stolendata" defaultValue="none" /> </> ); ``` ### Patches Versions 3.19.12 and 4.7.6 now use `DOMPurify` to escape the HTML before outputting it with React and `dangerouslySetInnerHTML` ### Workarounds You don't need to upgrade if you already sanitize HTML data server-side. Otherwise, you'll have to replace the `<RichTextField>` by a custom field doing sanitization by hand: ```tsx // react-admin v4 import * as React from 'react'; import { memo } from 'react'; import PropTypes from 'prop-types'; import get from 'lodash/get'; import Typography from '@material-ui/core/Typography'; import { useRecordContext, sanitizeFieldRestProps, fieldPropTypes } from 'react-admin'; import purify from 'dompurify'; export const removeTags = (input) => input ? input.replace(/<[^>]+>/gm, '') : ''; const RichTextField = memo( props => { const { className, emptyText, source, stripTags, ...rest } = props; const record = useRecordContext(props); const value = get(record, source); return ( <Typography className={className} variant="body2" component="span" {...sanitizeFieldRestProps(rest)} > {value == null && emptyText ? ( emptyText ) : stripTags ? ( removeTags(value) ) : ( <span dangerouslySetInnerHTML={{ __html: purify.sanitize(value), }} /> )} </Typography> ); } ); RichTextField.defaultProps = { addLabel: true, stripTags: false, }; RichTextField.propTypes = { // @ts-ignore ...Typography.propTypes, ...fieldPropTypes, stripTags: PropTypes.bool, }; RichTextField.displayName = 'RichTextField'; export default RichTextField; ``` ### References https://github.com/marmelab/react-admin/pull/8644, https://github.com/marmelab/react-admin/pull/8645

Metadata

Created: 2023-02-14T00:32:21Z
Modified: 2023-02-14T00:32:21Z
Source: https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2023/02/GHSA-5jcr-82fh-339v/GHSA-5jcr-82fh-339v.json
CWE IDs: ["CWE-79"]
Alternative ID: GHSA-5jcr-82fh-339v
Finding: F008
Auto approve: 1