Safeguard
Security Guides•

Which XSS sinks should you review in React, Vue and Angular?

One table of the escape hatches to search for in React, Vue and Angular code, what each does, and how to review it. Use it as a pull request checklist.

Safeguard Security Team
4 min read

Search for the escape hatches that skip each framework's escaping: dangerouslySetInnerHTML in React, v-html and innerHTML in Vue, and innerHTML bindings plus the bypassSecurityTrust methods in Angular. Add direct DOM access, string templates and eval. Each hit needs a known, trusted or sanitized source.

Definitions

A sink is a place where data becomes live page content: HTML, a URL, a style or code. XSS happens when attacker-controlled data reaches a sink without being encoded or sanitized for that context. Modern frameworks make the default sinks safe and leave a short list of deliberate ones.

OWASP's JavaScript and TypeScript cheat sheet names the main bypasses that must never receive untrusted input: React dangerouslySetInnerHTML, Vue v-html and Angular bypassSecurityTrustHtml and its siblings. It also advises building DOM with textContent and createElement instead of innerHTML or insertAdjacentHTML.

The review table

SinkFrameworkWhat it doesReview question
dangerouslySetInnerHTMLReactOverrides innerHTML with a raw HTML stringWhere does the string come from, and is it sanitized?
v-html or innerHTML propVueRenders raw HTML, bypassing escapingIs the source trusted or sanitized?
Binding to innerHTMLAngularInterprets HTML but Angular still sanitizes itIs a bypass call also involved?
bypassSecurityTrust methodsAngularTells Angular to stop sanitizingIs the value fully controlled, and the context correct?
href and src from dataAllCan carry a javascript: URLIs the scheme and host validated?
Direct DOM through refs or ElementRefAllSkips framework protectionDoes it use innerHTML or insertAdjacentHTML?
Template built from stringsVue, AngularCompiles attacker text as codeIs user text ever in a template?
eval, new Function, string timersAllRuns code from stringsCan any input reach them?
Style bindings from usersAllEnables clickjacking style tricksAre only specific properties allowed?

How to run the review

  1. Grep for each sink name from the table across source and templates.
  2. For every hit, trace the value back to its origin and label it: constant, trusted internal, sanitized, or unknown.
  3. Fix unknowns first: replace with text rendering, or sanitize with a maintained library and do not edit afterwards.
  4. Add lint rules for the most common sinks. The react/no-danger rule and Vue's vue/no-v-html rule exist for this, and both can be disabled where content is known to be sanitized.
  5. Add the no-eval, no-implied-eval and no-new-func rules that OWASP recommends.
  6. Add a pull request prompt: "Did this change add or touch a sink from the table?"

Defense in depth

Frameworks guard the DOM. A content security policy and Trusted Types guard it from outside the framework. The Angular guide says these work at the DOM level, the most effective place to prevent XSS, where they cannot be bypassed by lower level APIs. For Trusted Types in Angular, see the policy names explained.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how each finding records a file and line, like one row in the sink review above.

Safeguard's free scan at gold.safeguard.sh/scan covers dependencies, which also carry sinks of their own.

Quick check

Is innerHTML always bad?

It is a sink. It is fine with trusted constants and risky with anything an attacker can influence. Prefer textContent when you only need text.

Do lint rules replace review?

No. They find the sinks. A person still decides whether each source is safe.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.