Skip to content

Commit 4468e3c

Browse files
committed
refactor(VSelect): render highlight with vnodes instead of innerHTML
Prevents possible XSS vulnerability
1 parent ade1434 commit 4468e3c

File tree

2 files changed

+10
-25
lines changed

2 files changed

+10
-25
lines changed

packages/vuetify/src/components/VSelect/VSelectList.ts

+10-15
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ import Colorable from '../../mixins/colorable'
1818
import Themeable from '../../mixins/themeable'
1919

2020
// Helpers
21-
import {
22-
escapeHTML,
23-
getPropertyFromItem,
24-
} from '../../util/helpers'
21+
import { getPropertyFromItem } from '../../util/helpers'
2522

2623
// Types
2724
import mixins from '../../util/mixins'
@@ -113,17 +110,17 @@ export default mixins(Colorable, Themeable).extend({
113110
genFilteredText (text: string) {
114111
text = text || ''
115112

116-
if (!this.searchInput || this.noFilter) return escapeHTML(text)
113+
if (!this.searchInput || this.noFilter) return text
117114

118115
const { start, middle, end } = this.getMaskedCharacters(text)
119116

120-
return `${escapeHTML(start)}${this.genHighlight(middle)}${escapeHTML(end)}`
117+
return [start, this.genHighlight(middle), end]
121118
},
122119
genHeader (props: { [key: string]: any }): VNode {
123120
return this.$createElement(VSubheader, { props }, props.header)
124121
},
125-
genHighlight (text: string): string {
126-
return `<span class="v-list-item__mask">${escapeHTML(text)}</span>`
122+
genHighlight (text: string) {
123+
return this.$createElement('span', { staticClass: 'v-list__tile__mask' }, text)
127124
},
128125
getMaskedCharacters (text: string): {
129126
start: string
@@ -202,13 +199,11 @@ export default mixins(Colorable, Themeable).extend({
202199
: scopedSlot
203200
},
204201
genTileContent (item: any, index = 0): VNode {
205-
const innerHTML = this.genFilteredText(this.getText(item))
206-
207-
return this.$createElement(VListItemContent,
208-
[this.$createElement(VListItemTitle, {
209-
domProps: { innerHTML },
210-
})]
211-
)
202+
return this.$createElement(VListItemContent, [
203+
this.$createElement(VListItemTitle, [
204+
this.genFilteredText(this.getText(item)),
205+
]),
206+
])
212207
},
213208
hasItem (item: object) {
214209
return this.parsedItems.indexOf(this.getValue(item)) > -1

packages/vuetify/src/util/helpers.ts

-10
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,6 @@ export function getZIndex (el?: Element | null): number {
162162
return index
163163
}
164164

165-
const tagsToReplace = {
166-
'&': '&amp;',
167-
'<': '&lt;',
168-
'>': '&gt;',
169-
} as any
170-
171-
export function escapeHTML (str: string): string {
172-
return str.replace(/[&<>]/g, tag => tagsToReplace[tag] || tag)
173-
}
174-
175165
export function filterObjectOnKeys<T, K extends keyof T> (obj: T, keys: K[]): { [N in K]: T[N] } {
176166
const filtered = {} as { [N in K]: T[N] }
177167

0 commit comments

Comments
 (0)