fix(refinementList): prevent XSS via routing #4344
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There's a security issue with the
refinementList
widget when relying on its default template and routing.Security issue demonstration →
Why this is an issue
Malicious users could inject some JavaScript code via the URL to get specific information. This is Cross-Site Scripting (XSS) vulnerability.
Why this happens
We use
{{{highlighted}}}
in the defaultitem
template of therefinementList
widget. The triple braces in Hogan.js means that it doesn't escape the value, and uses thesetInnerHTML
method under the hood. Therefore, HTML can be injected. The issue comes from the fact that we allow users to select refinement list items from the URL, which means that it's not safe to use this method.We use triple braces in the template because when SFFV (Searching For Facet Values), we highlight the matches with HTML tags. This specific case is not as dangerous because we don't synchronize the SFFV values in the URL.
This solution
We can switch to using
{{highlighted}}
by default. This means that HTML won't be interpreted. When we detect that we're coming from a search (props.isFromSearch
in theRefinementList
component), we can safely rely on{{{highlighted}}}
because SFFV are not synced with the URL.We therefore conditionally use the "dangerous" value when it cannot come from the URL.
Migration plan
This solution is the one that I think will be the less transparent for users. Very few (if not none) users must rely on facet values containing HTML and the triple brace Hogan syntax. If so, this fix is more important than considering this as a breaking change to speed up the adoption of the next minor version. We'll therefore be explicit about this security fix in the changelog if ever it breaks some apps, which again, is very unlikely.
Other considerations
Vue InstantSearch is vulnerable to the same attack. This happens because we rely on
innerHTML
in theais-highlight
component.We should be more careful with values generated from the URL. This will also be true with values injected in the UI state more generally. We should think about rejecting values that cannot happen, since you're not supposed to be able to generate facet values via the URL. This is out of scope for now.
We can delay the documentation for this new
isFromSearch
template property. We shouldn't wait for the documentation update in thetemplates
section before releasing a new version.