React escapes already escaped string

Issue

I have an app that uses Express + mongoose as its backend, and React as its frontend. On the backend, the validation of user input is done by express-validator the following way:

body('text')
      .trim()
      .escape()
      .not()
      .isEmpty()
      .withMessage('Comment should contain something, right?'),

The mongoose model schema:

const commentSchema = new Schema<IComment>({
  author: String,
  post: {
    type: SchemaTypes.ObjectId,
    ref: 'Post',
  },
  text: {
    type: String,
  },
  date: Date,
});

The text and author properties are what I have trouble with. I made sure the data comes to the backend unescaped, and from the backend it comes escaped (and only once, by express-validator). However, when I try to render in React a string coming from the backend like that's the (it contains ' character), it’s rendered in the browser as that&#x27;s the. When I inspected the element, I found that the ampersand has been replaced with &amp, and the string ended up being displayed exactly the way it came from the backend. It appears that the ampersand was doubly escaped. Is there a way to prevent this without installing any external libraries and using dangerouslySetInnerHTML? I just don’t want this ampersand to be escaped. My assumption is that it’s done by React.
The component has the following structure:

   <Wrapper>
      <Author>{author}</Author>
      <Text>{text}</Text>
      <Date>{date}</Date>
    </Wrapper>

Same happens if I insert all the values in a plain <div>.


EDIT: If I hardcode something like &lt;html&gt; right into the JSX tag, everything works fine. If I hardcode {"&lt;html&gt;"}, this is treated as a string and is escaped. The data coming from the backend is, well, string, but already escaped.

Solution

Just send plain unescaped strings from back-end.
It should be front-end who decides how to render and whether to escape the data, and unless you use dangerouslySetInnerHTML you are safe.

Let’s say somebody has written a comment containing xss script. You can save the comment in a database as is, and then React will automatically escape it for you, so that script will never be evaluated (again, unless you use dangerouslySetInnerHTML to render the comment).

Answered By – Yuriy Yakym

Answer Checked By – Gilberto Lyons (AngularFixing Admin)

Leave a Reply

Your email address will not be published.