# Node-RED Config Node Tooltip: Multi-line Rendering and XSS Protection

**URL:** <https://discourse.nodered.org/t/node-red-config-node-tooltip-multi-line-rendering-and-xss-protection/100412>\
**Category:** Core Development\
**Tags:** node-red-dashboard\
**Created:** [19 February 2026 11:48 UTC](https://discourse.nodered.org/t/node-red-config-node-tooltip-multi-line-rendering-and-xss-protection/100412 "2026-02-19T11:48:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![malee](https://avatars.discourse-cdn.com/v4/letter/m/ac8455/32.png) [@malee](https://discourse.nodered.org/u/malee)\
**Post date:** [19 February 2026 11:48 UTC](https://discourse.nodered.org/t/node-red-config-node-tooltip-multi-line-rendering-and-xss-protection/100412/1 "2026-02-19T11:48:54Z")

</div>

There is a fix for rendering multi-line tooltips for config node validation errors in Node-RED, this explains how the approach preserves security against Cross-Site Scripting (XSS) vulnerabilities.

* * *

## 1. Problem: HTML Escaping and Usability

- Previously, config node error tooltips used a string with `<br>` tags to indicate line breaks.
- Due to the popover implementation, all function-returned strings were rendered using `.text()`, escaping HTML, so `<br>` appeared as literal text.
- Rendering as HTML (with `.html()`) would allow line breaks, but would also introduce XSS risk if any part of the message was user-controlled.

* * *

## 2. The Fix: Array-based Multi-line Tooltips

### Implementation

- The error message is now passed as an array:
  - The first element is the main error label (e.g., "Invalid properties:").
  - Each subsequent element is a validation error (e.g., `" - authUrl"`).

- The popover script was updated to detect arrays:
  - Each array element is rendered as a text node.
  - A line break (`<br>`) is inserted between each line.
  - No HTML is interpreted from the error strings themselves.

#### Example

```js
const errorMsg = [
  RED._("editor.errors.invalidProperties"),
  ...node.validationErrors.map(e => " - " + e)
];
RED.popover.tooltip(target, errorMsg);

```

Popover rendering logic:

```js
if (typeof result === 'string') {
    contentDiv.text(result);
} else if (Array.isArray(result)) {
    result.forEach(function(line, idx) {
        if (idx > 0) contentDiv.append(document.createElement('br'));
        contentDiv.append(document.createTextNode(line));
    });
} else {
    contentDiv.append(result);
}

```

* * *

## 3. Security: XSS Protection

- **No HTML is ever interpreted from the error message array.**
- Each line is rendered using `document.createTextNode(line)`, which escapes all HTML and JavaScript.
- Even if a validation error contains user-controlled content (e.g., a property name like `<img src=x onerror=alert(1)>`), it will be displayed as plain text, not executed.
- This approach is as safe as the original `.text()` rendering, but allows for visually clean, multi-line tooltips.

* * *

## 4. Result

- Tooltips for config node errors now display each error on its own line, improving readability and usability.
- The code remains robust against XSS, as no user input is ever rendered as HTML.
- This pattern can be safely reused for any tooltip content that requires multi-line display and may include user input.

* * *

## 5. References

- [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
- [jQuery .text() vs .html()](https://api.jquery.com/text/)

* * *

Is this something that is worth creating a PR for, I figure it is a non-breaking change.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [19 February 2026 12:39 UTC](https://discourse.nodered.org/t/node-red-config-node-tooltip-multi-line-rendering-and-xss-protection/100412/2 "2026-02-19T12:39:50Z")

</div>

An alternative would be simply to use html instead of text but pass it through Node-RED's built in DOMPurify function.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [20 April 2026 12:40 UTC](https://discourse.nodered.org/t/node-red-config-node-tooltip-multi-line-rendering-and-xss-protection/100412/3 "2026-04-20T12:40:13Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
