htmlSafe
marks a string as safe for unescaped output with Ember templates so you can render it as HTML. htmlSafe
does not perform input sanitization. While useful this can inadvertently open you up to Cross-site Scripting (XSS) vulnerabilities, especially if the string was generated from user input or some other untrusted source. You should only ever use htmlSafe
with trusted or sanitized input.
Note: this rule is not in the recommended
configuration because there are legitimate usages of htmlSafe
.
This rule prevents importing the htmlSafe
utillity from @ember/template
(or @ember/string
for older Ember versions);
Examples of incorrect code for this rule:
import { htmlSafe } from '@ember/template';
import { htmlSafe } from '@ember/string';
There are a few alternative strategies to using htmlSafe
.
In this example we have a property userContent
which contains a user-generated string of HTML. For example, something like <h1>Joe Bloggs</h1>
. This is then rendered directly into the template.
// components/my-component.js
import { htmlSafe } from '@ember/template';
class MyComponent extends Component {
get myContent() {
return htmlSafe(this.args.userContent);
}
}
While not as flexible, if you can control the content generated by the user you should only let the user enter plaintext and render the HTML yourself.
If you have to render user generated HTML, you should protect yourself by always sanitizing the input first. One strategy is to, rather than have usage of htmlSafe
proliferated throughout your app, isolate it to a single location and combine it with a sanitization library, e.g. DOMPurify. Then require all HTML strings go through this helper. If this helper is in the same codebase where the no-html-safe
lint rule is enabled, you can disable the rule for this single location.
// app/lib/sanitized-content.js
import { htmlSafe } from '@ember/template';
export function sanitizedContent(content) {
const sanitized = someSanitizationLibrary(content);
return htmlSafe(sanitized);
}
// app/components/my-component.js
import { sanitizedContent } from 'my-app/lib/sanitized-content';
class MyComponent extends Component {
get myContent() {
return sanitizedContent(this.args.userContent);
}
}
This is similar to the previous example but in this case you could create a Handlebars helper which sanitizes your input.
// app/helpers/sanitize.js
import { htmlSafe } from '@ember/template';
import { helper } from '@ember/component/helper';
function sanitize([content]) {
const sanitized = someSanitizationLibrary(content);
return htmlSafe(sanitized);
}
export default helper(substring);
- ember-template-lint has a no-triple-curlies rule for the template equivalent of this rule.