In February 2023, security researchers discovered a critical DOM-based Cross-Site Scripting (XSS) vulnerability in rails-ujs (Unobtrusive JavaScript adapter for Rails). This issue, tracked as CVE-2023-23913, leverages the Clipboard API to target HTML elements assigned the contenteditable attribute. If a user pastes malicious HTML containing certain Rails data attributes into a contenteditable area, it can lead to XSS—executing unauthorized scripts in the context of the website.

Let's break down what happened, see a proof-of-concept, and understand how to stay protected.

[Am I Affected?](#am-i-affected)

6. [How to Fix / Patch](#how-to-fix)

What's rails-ujs?

rails-ujs is the default JavaScript library in Rails that enables special behaviors via data attributes, such as:

<a data-method="delete" href="/posts/1">Delete</a>
<button data-remote="true">Submit AJAX</button>

rails-ujs scans for these attributes and adds event listeners to implement features like "delete", "remote", and "data-disable-with" buttons.

Understanding the Vulnerability

When a user pastes HTML into a contenteditable area (like a rich text editor) in a Rails app, modern browsers may allow HTML from the clipboard to be inserted as-is. rails-ujs uses event delegation and may automatically upgrade certain elements matching data-method, data-remote, or data-disable-with attributes—even if they were pasted in, not originally rendered by your app.

`html

Click me

`

2. This HTML is copied to the clipboard, and a victim is tricked into pasting it into a contenteditable area on a vulnerable Rails site.
3. rails-ujs detects these newly inserted elements (because it uses event delegation) and enables AJAX or method spoofing features.

If a user clicks the pasted button, the malicious JavaScript runs.

This is known as a DOM-based XSS, since the evil HTML never passed through the server.

Let's see a simple exploit. Try following along on a test Rails app with a template like this

<div id="editor" contenteditable="true" style="border:1px solid #ccc;padding:10px;">
  Paste content here...
</div>

Now, suppose the attacker sends you this HTML to copy

<button data-remote="true" data-url="javascript:alert('XSS via rails-ujs');">
  Click me!
</button>

Click the pasted button.

If your rails-ujs version is vulnerable and remote forms are enabled, clicking the button will trigger the JavaScript payload (alert('XSS via rails-ujs')).

Why does this work?

- rails-ujs "upgrades" elements *regardless* of source—server-rendered or user-pasted—in contenteditable regions.

References

- Rails Security Advisory 2023-02-08
- GitHub commit fixing the issue
- NIST NVD entry for CVE-2023-23913
- Original bug report

You have contenteditable areas where users can paste HTML or rich text.

You are not safe just because your app filters user input on the backend. Data pasted into the DOM via contenteditable can bypass server-side validations, leading to DOM-based XSS attacks.

Rails 6..6.1

2. If you cannot upgrade, you can mitigate by disabling "data-remote", "data-method", and "data-disable-with" on elements inside contenteditable areas, or strip them from pasted content:

if(!clipboard) return;

// Parse pasted HTML
const pastedHTML = clipboard.getData('text/html');

e.preventDefault();

// Create DOM

temp.innerHTML = pastedHTML;

// Remove dangerous attributes

});

// Insert sanitized HTML

Conclusion

CVE-2023-23913 is a clear reminder: client-side security matters, especially when copying and pasting HTML in "rich text" features. Untrusted HTML with dangerous Rails data attributes can bypass your server and force the browser to do dangerous things!

Always update to the latest Rails version. If you must support rich editors, sanitize input on the client, too.

Stay safe!

*This post was prepared exclusively for your security awareness. For more info, read the Rails official advisory and always keep dependencies patched.*

Timeline

Published on: 01/09/2025 01:15:07 UTC
Last modified on: 01/09/2025 18:15:24 UTC