Skip to content

Commit

Permalink
fix(surveys): allow target attributes for html (#18532)
Browse files Browse the repository at this point in the history
  • Loading branch information
liyiy authored Nov 9, 2023
1 parent 38d366d commit 30df1e7
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 9 deletions.
20 changes: 11 additions & 9 deletions frontend/src/scenes/surveys/SurveyAppearance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {
import { surveysLogic } from './surveysLogic'
import { useValues } from 'kea'
import React, { useEffect, useRef, useState } from 'react'
import { sanitize } from 'dompurify'
import { PayGateMini } from 'lib/components/PayGateMini/PayGateMini'
import { sanitizeHTML } from './utils'

interface SurveyAppearanceProps {
type: SurveyQuestionType
Expand Down Expand Up @@ -284,12 +284,12 @@ export function BaseAppearance({
</div>
)}
<div className="question-textarea-wrapper">
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitize(question) }} />
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitizeHTML(question) }} />
{/* Using dangerouslySetInnerHTML is safe here, because it's taking the user's input and showing it to the same user.
They can try passing in arbitrary scripts, but it would show up only for them, so it's like trying to XSS yourself, where
you already have all the data. Furthermore, sanitization should catch all obvious attempts */}
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitize(description) }} />
<div className="description" dangerouslySetInnerHTML={{ __html: sanitizeHTML(description) }} />
)}
{type === SurveyQuestionType.Open && (
<textarea
Expand Down Expand Up @@ -491,9 +491,9 @@ export function SurveyRatingAppearance({
</button>
</div>
)}
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitize(question) }} />
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitizeHTML(question) }} />
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitize(description) }} />
<div className="description" dangerouslySetInnerHTML={{ __html: sanitizeHTML(description) }} />
)}
<div className="rating-section">
<div className="rating-options">
Expand Down Expand Up @@ -591,9 +591,9 @@ export function SurveyMultipleChoiceAppearance({
</button>
</div>
)}
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitize(question) }} />
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitizeHTML(question) }} />
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitize(description) }} />
<div className="description" dangerouslySetInnerHTML={{ __html: sanitizeHTML(description) }} />
)}
<div className="multiple-choice-options">
{(multipleChoiceQuestion.choices || []).map((choice, idx) => (
Expand Down Expand Up @@ -659,11 +659,13 @@ export function SurveyThankYou({ appearance }: { appearance: SurveyAppearanceTyp
</div>
<h3
className="thank-you-message-header"
dangerouslySetInnerHTML={{ __html: sanitize(appearance?.thankYouMessageHeader || 'Thank you!') }}
dangerouslySetInnerHTML={{
__html: sanitizeHTML(appearance?.thankYouMessageHeader || 'Thank you!'),
}}
/>
<div
className="thank-you-message-body"
dangerouslySetInnerHTML={{ __html: sanitize(appearance?.thankYouMessageDescription || '') }}
dangerouslySetInnerHTML={{ __html: sanitizeHTML(appearance?.thankYouMessageDescription || '') }}
/>
<Button appearance={appearance} onSubmit={() => undefined}>
Close
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/scenes/surveys/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { sanitize } from 'dompurify'

const sanitizeConfig = { ADD_ATTR: ['target'] }

export function sanitizeHTML(html: string): string {
return sanitize(html, sanitizeConfig)
}

0 comments on commit 30df1e7

Please sign in to comment.