Skip to content

unsafe-markup-use (RUF035)

This rule is unstable and in preview. The --preview flag is required for use.

What it does

Checks for non-literal strings being passed to markupsafe.Markup.

Why is this bad?

markupsafe.Markup does not perform any escaping, so passing dynamic content, like f-strings, variables or interpolated strings will potentially lead to XSS vulnerabilities.

Instead you should interpolate the markupsafe.Markup object.

Using lint.ruff.extend-markup-names additional objects can be treated like markupsafe.Markup.

This rule was originally inspired by flake8-markupsafe but doesn't carve out any exceptions for i18n related calls.

Example

Given:

from markupsafe import Markup

content = "<script>alert('Hello, world!')</script>"
html = Markup(f"<b>{content}</b>")  # XSS

Use instead:

from markupsafe import Markup

content = "<script>alert('Hello, world!')</script>"
html = Markup("<b>{}</b>").format(content)  # Safe

Given:

from markupsafe import Markup

lines = [
    Markup("<b>heading</b>"),
    "<script>alert('XSS attempt')</script>",
]
html = Markup("<br>".join(lines))  # XSS

Use instead:

from markupsafe import Markup

lines = [
    Markup("<b>heading</b>"),
    "<script>alert('XSS attempt')</script>",
]
html = Markup("<br>").join(lines)  # Safe

Options

References