In the bad old days, all user-supplied text in a web page was entered using one or other form element,
input for short texts such as names, and
textarea for texts that may span multiple lines, such as comments or user feedback. These elements, while extremely useful and serviceable, didn’t always fit in with the webpages they occupied, and had no capacity for WYSIWYG editing of formatted text.
But now, using the
contentEditable attribute (one of HTML5’s many innovations) almost any element on the page can be used for user-supplied text. This is used to great effect in Matthew Butterick’s font demos and the Medium post editor.
The real power of
contentEditable is the way it seamlessly blends editable content into a webpage. As an example, click anywhere in this paragraph and put some words in my mouth. Neat, eh?
But there’s more! Once you’ve had your full of editing my words, try selecting and dragging some of this styled text into the editable paragraph above. See what happens? The formatting is preserved! And that’s how it’s possible to use
contentEditable to create rich text editors in the web browser. Because
contentEditable is just an attribute you can attach to any element, rather than a special text-input box, it can contain any HTML the browser will render.
I emphasis the word any because that any includes
<script> tags, and should thus be setting alarm bells off in the minds of anyone who knows about Cross-Site Scripting (XSS for short). What’s interesting here is that, unlike your standard
textarea boxes, a
contentEditable element will automatically HTML entity encode dangerous elements like
An initial, naive XSS test of just typing
<script>alert(1)</script> into a
contentEditable and submitting it to the server for inclusion in the page on a refresh will fail. If HTML entities are being encoded on the server side (as they should be), you’ll end up with the ugliness of double-encoded characters, i.e.
This could prompt you to remove your server-side entity encoding. But try the drag test, and you’ll get some nice HTML injection, so rather keep your validation.
HTML injection: it may seem like XSS’s lame younger brother, but it can still do a lot of damage. There’s a lot you can do with HTML – imagine using stored HTML injection to insert a banner reading “We are closing down soon, please deactivate your account” just above a login page, for example.