Escape HTML in local API text runs to prevent XSS (#3675)

This commit is contained in:
absidue 2023-06-19 19:01:12 +02:00 committed by GitHub
parent e97e1a1459
commit 3c6e1d1a8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 8 deletions

View File

@ -9,6 +9,7 @@ import { MAIN_PROFILE_ID } from '../../../constants'
import { calculateColorLuminance, getRandomColor } from '../../helpers/colors'
import {
copyToClipboard,
escapeHTML,
getTodayDateStrLocalTimezone,
readFileFromDialog,
showOpenDialog,
@ -587,12 +588,7 @@ export default defineComponent({
let opmlData = '<opml version="1.1"><body><outline text="YouTube Subscriptions" title="YouTube Subscriptions">'
this.profileList[0].subscriptions.forEach((channel) => {
const escapedName = channel.name
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll('\'', '&apos;')
const escapedName = escapeHTML(channel.name)
const channelOpmlString = `<outline text="${escapedName}" title="${escapedName}" type="rss" xmlUrl="https://www.youtube.com/feeds/videos.xml?channel_id=${channel.id}"/>`
opmlData += channelOpmlString

View File

@ -5,6 +5,7 @@ import { join } from 'path'
import { PlayerCache } from './PlayerCache'
import {
CHANNEL_HANDLE_REGEX,
escapeHTML,
extractNumberFromString,
getUserDataPath,
toLocalePublicationString
@ -551,8 +552,12 @@ export function parseLocalTextRuns(runs, emojiSize = 16, options = { looseChanne
const parsedRuns = []
for (const run of runs) {
// may contain HTML, so we need to escape it, as we don't render unwanted HTML
// example: https://youtu.be/Hh_se2Zqsdk (see pinned comment)
const text = escapeHTML(run.text)
if (run instanceof Misc.EmojiRun) {
const { emoji, text } = run
const { emoji } = run
// empty array if video creator removes a channel emoji so we ignore.
// eg: pinned comment here https://youtu.be/v3wm83zoSSY
@ -577,7 +582,7 @@ export function parseLocalTextRuns(runs, emojiSize = 16, options = { looseChanne
parsedRuns.push(`<img src="${emoji.image[0].url}" alt="${altText}" width="${emojiSize}" height="${emojiSize}" loading="lazy" style="vertical-align: middle">`)
}
} else {
const { text, bold, italics, strikethrough, endpoint } = run
const { bold, italics, strikethrough, endpoint } = run
if (endpoint) {
switch (endpoint.metadata.page_type) {

View File

@ -646,3 +646,16 @@ export function getTodayDateStrLocalTimezone() {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
return timeNowStr.split('T')[0]
}
/**
* Escapes HTML tags to avoid XSS
* @param {string} untrusted
* @returns {string}
*/
export function escapeHTML(untrusted) {
return untrusted.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll('\'', '&apos;')
}