typescript.react.security.audit.react-dangerouslysetinnerhtml.react-dangerouslysetinnerhtml
Verifed by r2c
Community Favorite

Author
64,103
Download Count*
License
Detection of dangerouslySetInnerHTML from non-constant definition. This can inadvertently expose users to cross-site scripting (XSS) attacks if this comes from user-provided input. If you have to use dangerouslySetInnerHTML, consider using a sanitization library such as DOMPurify to sanitize your HTML.
Run Locally
Run in CI
Defintion
rules:
- id: react-dangerouslysetinnerhtml
message: Detection of dangerouslySetInnerHTML from non-constant definition. This
can inadvertently expose users to cross-site scripting (XSS) attacks if
this comes from user-provided input. If you have to use
dangerouslySetInnerHTML, consider using a sanitization library such as
DOMPurify to sanitize your HTML.
metadata:
cwe:
- "CWE-79: Improper Neutralization of Input During Web Page Generation
('Cross-site Scripting')"
owasp:
- A07:2017 - Cross-Site Scripting (XSS)
- A03:2021 - Injection
references:
- https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html
category: security
confidence: MEDIUM
technology:
- react
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- vuln
likelihood: MEDIUM
impact: MEDIUM
vulnerability_class:
- Cross-Site-Scripting (XSS)
languages:
- typescript
- javascript
severity: WARNING
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern-inside: |
function ...({..., $X, ...}) { ... }
- pattern-inside: |
function ...(..., $X, ...) { ... }
- focus-metavariable: $X
- pattern-not-inside: |
$F. ... .$SANITIZEUNC(...)
pattern-sinks:
- patterns:
- focus-metavariable: $X
- pattern-either:
- pattern: |
{...,dangerouslySetInnerHTML: {__html: $X},...}
- pattern: |
<$Y ... dangerouslySetInnerHTML={{__html: $X}} />
- pattern-not: |
<$Y ... dangerouslySetInnerHTML={{__html: "..."}} />
- pattern-not: |
{...,dangerouslySetInnerHTML:{__html: "..."},...}
- metavariable-pattern:
patterns:
- pattern-not: |
{...}
metavariable: $X
- pattern-not: |
<... {__html: "..."} ...>
- pattern-not: |
<... {__html: `...`} ...>
pattern-sanitizers:
- patterns:
- pattern-either:
- pattern-inside: |
import $S from "underscore.string"
...
- pattern-inside: |
import * as $S from "underscore.string"
...
- pattern-inside: |
import $S from "underscore.string"
...
- pattern-inside: |
$S = require("underscore.string")
...
- pattern-either:
- pattern: $S.escapeHTML(...)
- patterns:
- pattern-either:
- pattern-inside: |
import $S from "dompurify"
...
- pattern-inside: |
import { ..., $S,... } from "dompurify"
...
- pattern-inside: |
import * as $S from "dompurify"
...
- pattern-inside: |
$S = require("dompurify")
...
- pattern-inside: |
import $S from "isomorphic-dompurify"
...
- pattern-inside: |
import * as $S from "isomorphic-dompurify"
...
- pattern-inside: |
$S = require("isomorphic-dompurify")
...
- pattern-either:
- patterns:
- pattern-inside: |
$VALUE = $S(...)
...
- pattern: $VALUE.sanitize(...)
- patterns:
- pattern-inside: |
$VALUE = $S.sanitize
...
- pattern: $S(...)
- pattern: $S.sanitize(...)
- pattern: $S(...)
- patterns:
- pattern-either:
- pattern-inside: |
import $S from 'xss';
...
- pattern-inside: |
import * as $S from 'xss';
...
- pattern-inside: |
$S = require("xss")
...
- pattern: $S(...)
- patterns:
- pattern-either:
- pattern-inside: |
import $S from 'sanitize-html';
...
- pattern-inside: |
import * as $S from "sanitize-html";
...
- pattern-inside: |
$S = require("sanitize-html")
...
- pattern: $S(...)
- patterns:
- pattern-either:
- pattern-inside: |
$S = new Remarkable()
...
- pattern: $S.render(...)
Examples
react-dangerouslysetinnerhtml.jsx
import DOMPurify from "dompurify"
import sanitize from "xss"
function TestComponent1() {
// ok:react-dangerouslysetinnerhtml
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
function TestComponent2(foo) {
// ruleid:react-dangerouslysetinnerhtml
let params = {smth: 'test123', dangerouslySetInnerHTML: {__html: foo.bar},a:b};
return React.createElement('div', params);
}
// ok:react-dangerouslysetinnerhtml
{collaborationSectionData.paragraphs.map((item, i) => (
<li key={`collaboration-p-${i}`} dangerouslySetInnerHTML={{
__html: item,}}>
</li>
))}
function TestComponent3() {
// ok:react-dangerouslysetinnerhtml
return <li className={"foobar"} dangerouslySetInnerHTML={{__html: params}} />;
}
function OkComponent1() {
// ok:react-dangerouslysetinnerhtml
return <li className={"foobar"} dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(foo)}} />;
}
function OkComponent2() {
// ok:react-dangerouslysetinnerhtml
return <li className={"foobar"} dangerouslySetInnerHTML={DOMPurify.sanitize(createMarkup())} />;
}
function OkComponent3() {
// ok:react-dangerouslysetinnerhtml
let params = {smth: 'test123', dangerouslySetInnerHTML: {__html: sanitize(foo)},a:b};
return React.createElement('div', params);
}
function OkComponent4() {
// ok:react-dangerouslysetinnerhtml
let params = {smth: 'test123', dangerouslySetInnerHTML: {__html: "hi"},a:b};
return React.createElement('div', params);
}
function OkComponent5() {
// ok:react-dangerouslysetinnerhtml
return <li class="foobar" selected={true} />;
}
function OkComponent6() {
// ok:react-dangerouslysetinnerhtml
let params = {smth: "test123", style: {color: 'red'}};
return React.createElement('div', params);
}
react-dangerouslysetinnerhtml.tsx
import DOMPurify from "dompurify"
import sanitize from "xss"
function TestComponent1() {
// ok:react-dangerouslysetinnerhtml
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
function TestComponent2(foo) {
// ruleid:react-dangerouslysetinnerhtml
let params = {smth: 'test123', dangerouslySetInnerHTML: {__html: foo.bar},a:b};
return React.createElement('div', params);
}
// ok:react-dangerouslysetinnerhtml
{collaborationSectionData.paragraphs.map((item, i) => (
<li key={`collaboration-p-${i}`} dangerouslySetInnerHTML={{
__html: item,}}>
</li>
))}
function TestComponent3() {
// ok:react-dangerouslysetinnerhtml
return <li className={"foobar"} dangerouslySetInnerHTML={{__html: params}} />;
}
function OkComponent1() {
// ok:react-dangerouslysetinnerhtml
return <li className={"foobar"} dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(foo)}} />;
}
function OkComponent2() {
// ok:react-dangerouslysetinnerhtml
return <li className={"foobar"} dangerouslySetInnerHTML={DOMPurify.sanitize(createMarkup())} />;
}
function OkComponent3() {
// ok:react-dangerouslysetinnerhtml
let params = {smth: 'test123', dangerouslySetInnerHTML: {__html: sanitize(foo)},a:b};
return React.createElement('div', params);
}
function OkComponent4() {
// ok:react-dangerouslysetinnerhtml
let params = {smth: 'test123', dangerouslySetInnerHTML: {__html: "hi"},a:b};
return React.createElement('div', params);
}
function OkComponent5() {
// ok:react-dangerouslysetinnerhtml
return <li class="foobar" selected={true} />;
}
function OkComponent6() {
// ok:react-dangerouslysetinnerhtml
let params = {smth: "test123", style: {color: 'red'}};
return React.createElement('div', params);
}
Short Link: https://sg.run/rAx6