Yes. Flutter's own widgets show a string as text, so ordinary UI is not the risk. Cross-site scripting appears where your Dart code reaches the browser's DOM: embedded HTML elements, direct use of browser APIs, unvalidated link targets and the host page. Use text APIs, sanitize any HTML you must show, validate URLs and set a Content Security Policy.
Where do the sinks hide?
OWASP's cheat sheet says apps built with modern frameworks have fewer XSS bugs because templating and escaping steer developers well, then lists where problems still occur: escape hatches that manipulate the DOM directly, unvalidated URL values in src and href, and template injection. Flutter has its equivalents.
HtmlElementView. Flutter's documentation says web apps can render arbitrary web content inside a widget with HtmlElementView, and that you can create an element by tag name, configure it in a callback, or register your own element factory. Anything you put into that element is yours to make safe. If a factory builds markup from a string that came from a user, an API or a query parameter, you have created an HTML sink.
Browser API bindings. Dart's long-term web interop is package:web, which the package page describes as lightweight bindings generated from Web IDL, intended to replace dart:html. Because it exposes the browser's real properties, it exposes the dangerous ones as well. Setting inner HTML from untrusted text is the same bug in Dart as in JavaScript.
dart:html sanitizing. The older library has a more careful design. setInnerHtml parses a fragment and applies a validator or tree sanitizer so that the result contains only nodes and attributes the validator allows. Its builder class starts by accepting nothing and lets you add allowances, and the documentation notes that sanitization is also about stopping content from appearing in unexpected ways, for example a basic text display should not suddenly show video tags. Be careful with a trusted-HTML sanitizer that skips these rules.
Links. A tapped link opens whatever URL you give it. The OWASP guidance on URL attributes is that framework handling does not replace application specific validation. Accept only https and mailto schemes you expect, and reject javascript: and data URLs.
What does a safe pattern look like?
OWASP's rule for displaying text through scripts is to assign it to the textContent property of an ordinary element, not a markup property. In Dart, that means choosing the text setter whenever you only need text. If you truly need rich content, such as a help article, sanitize with an allowlist library, display it in a sandboxed frame, or render it as widgets by parsing it yourself with the html package, which is a Dart implementation of the HTML5 parser and works outside the browser.
The MDN guide to Trusted Types describes injection sinks in three families, HTML, JavaScript and JavaScript URL, and a policy mechanism that routes data through a transformation before it reaches a sink. A Content Security Policy that requires trusted types for scripts gives you a backstop for any sink that code review missed. Test your CSP against Flutter's own loading requirements before you enforce it.
A constructed example
A support app lets agents paste a message that customers see in a banner. The developer registers an element factory that sets the banner's inner HTML from the message so bold text works. A customer service message containing an image tag with an error handler runs script in every viewer's session. The fix has three parts: show the banner with plain text, allow bold through a small formatting syntax converted to widgets, and add a CSP that blocks inline script so the next mistake is less costly.
What to do
- Search your Dart code for
HtmlElementView,registerViewFactory,innerHTML,setInnerHtml,outerHTMLandinsertAdjacentHTML. - For each match, trace where the string comes from.
- Replace markup setters with text setters wherever only text is needed.
- If HTML is required, sanitize with a strict allowlist, and prefer parsing into widgets.
- Validate every URL scheme before launching a link or setting a source.
- Review the host
index.htmland any JavaScript interop for DOM writes. - Add a Content Security Policy and consider requiring trusted types.
- Keep
package:web,htmland your dependencies current, and scan them for known advisories.
Safeguard's static scan can flag risky sinks in source code, as in the SAST code scan demo.
Quick check
Is a Flutter Text widget vulnerable to XSS?
No. It displays the string as text and does not parse it as markup. The risk is in embedded HTML, raw DOM calls and links.
Does sanitizing HTML replace output encoding?
No. Encoding is for showing data as text. Sanitizing is for the case where you must allow some HTML, and it needs a strict allowlist.
Sources
- OWASP: Cross Site Scripting Prevention Cheat Sheet
- OWASP: DOM based XSS Prevention Cheat Sheet
- Flutter: Embedding web content into a Flutter web app
- Dart API: NodeValidatorBuilder
- Dart API: Element.setInnerHtml
- pub.dev: web package
- pub.dev: html package
- MDN: Trusted Types API
Last reviewed: 18 October 2026.