Found unsafe method `htmlSafe()`JS-S1007
htmlSafe
can lead to XSS vulnerabilities.
It can be used safely by following these approaches:
- Render the HTML yourself.
- Define your own trusted sanitizing helper.
- Define your own trusted sanitizing Handlebars helper.
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.
Bad Practice
import { htmlSafe } from '@ember/template';
import { htmlSafe } from '@ember/string';
Recommended
There are a few alternative strategies to using htmlSafe
.
In this first example, we have a property userContent
, which contains a valid user-generated HTML string.
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);
}
}
{{!-- components/my-component.hbs --}}
{{this.myContent}}
Approach 1: Render the HTML yourself
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.
{{!-- components/my-component.hbs --}}
<h1>{{@userContent}}</h1>
Approach 2: Define your own trusted sanitizing helper
If you have to render user generated HTML, you should protect yourself by always sanitizing the input first.
One possible approach could be to not have the use 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.
// 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);
}
}
{{!-- components/my-component.hbs --}}
{{this.myContent}}
Approach 3: Define your own trusted sanitizing Handlebars helper
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);
{{!-- components/my-component.hbs --}}
{{sanitize @userContent}}