mirror of https://github.com/astral-sh/ruff
## Summary Stop flagging each invocation of `django.utils.safestring.mark_safe` (also available at, `django.utils.html.mark_safe`) as an error. Instead, allow string literals as valid uses for `mark_safe`. Also, update the documentation, pointing at `django.utils.html.format_html` for dynamic content generation use cases. Closes #16702 ## Test Plan I verified several possible uses, but string literals, are still flagged. --------- Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
238ec39c56
commit
4da6936ec4
|
|
@ -1,8 +1,16 @@
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
|
||||||
def some_func():
|
def bad_func():
|
||||||
return mark_safe('<script>alert("evil!")</script>')
|
inject = "harmful_input"
|
||||||
|
mark_safe(inject)
|
||||||
|
mark_safe("I will add" + inject + "to my string")
|
||||||
|
mark_safe("I will add %s to my string" % inject)
|
||||||
|
mark_safe("I will add {} to my string".format(inject))
|
||||||
|
mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
||||||
|
def good_func():
|
||||||
|
mark_safe("I won't inject anything")
|
||||||
|
|
||||||
|
|
||||||
@mark_safe
|
@mark_safe
|
||||||
|
|
@ -13,8 +21,16 @@ def some_func():
|
||||||
from django.utils.html import mark_safe
|
from django.utils.html import mark_safe
|
||||||
|
|
||||||
|
|
||||||
def some_func():
|
def bad_func():
|
||||||
return mark_safe('<script>alert("evil!")</script>')
|
inject = "harmful_input"
|
||||||
|
mark_safe(inject)
|
||||||
|
mark_safe("I will add" + inject + "to my string")
|
||||||
|
mark_safe("I will add %s to my string" % inject)
|
||||||
|
mark_safe("I will add {} to my string".format(inject))
|
||||||
|
mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
||||||
|
def good_func():
|
||||||
|
mark_safe("I won't inject anything")
|
||||||
|
|
||||||
|
|
||||||
@mark_safe
|
@mark_safe
|
||||||
|
|
|
||||||
|
|
@ -344,21 +344,31 @@ impl Violation for SuspiciousEvalUsage {
|
||||||
/// before rending them.
|
/// before rending them.
|
||||||
///
|
///
|
||||||
/// `django.utils.safestring.mark_safe` marks a string as safe for use in HTML
|
/// `django.utils.safestring.mark_safe` marks a string as safe for use in HTML
|
||||||
/// templates, bypassing XSS protection. This is dangerous because it may allow
|
/// templates, bypassing XSS protection. Its usage can be dangerous if the
|
||||||
|
/// contents of the string are dynamically generated, because it may allow
|
||||||
/// cross-site scripting attacks if the string is not properly escaped.
|
/// cross-site scripting attacks if the string is not properly escaped.
|
||||||
///
|
///
|
||||||
|
/// For dynamically generated strings, consider utilizing
|
||||||
|
/// `django.utils.html.format_html`.
|
||||||
|
///
|
||||||
/// In [preview], this rule will also flag references to `django.utils.safestring.mark_safe`.
|
/// In [preview], this rule will also flag references to `django.utils.safestring.mark_safe`.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// from django.utils.safestring import mark_safe
|
/// from django.utils.safestring import mark_safe
|
||||||
///
|
///
|
||||||
/// content = mark_safe("<script>alert('Hello, world!')</script>") # XSS.
|
///
|
||||||
|
/// def render_username(username):
|
||||||
|
/// return mark_safe(f"<i>{username}</i>") # Dangerous if username is user-provided.
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Use instead:
|
/// Use instead:
|
||||||
/// ```python
|
/// ```python
|
||||||
/// content = "<script>alert('Hello, world!')</script>" # Safe if rendered.
|
/// from django.utils.html import format_html
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// def render_username(username):
|
||||||
|
/// return django.utils.html.format_html("<i>{}</i>", username) # username is escaped.
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
|
|
@ -1059,7 +1069,16 @@ fn suspicious_function(
|
||||||
["" | "builtins", "eval"] => SuspiciousEvalUsage.into(),
|
["" | "builtins", "eval"] => SuspiciousEvalUsage.into(),
|
||||||
|
|
||||||
// MarkSafe
|
// MarkSafe
|
||||||
["django", "utils", "safestring" | "html", "mark_safe"] => SuspiciousMarkSafeUsage.into(),
|
["django", "utils", "safestring" | "html", "mark_safe"] => {
|
||||||
|
if let Some(arguments) = arguments {
|
||||||
|
if let [single] = &*arguments.args {
|
||||||
|
if single.is_string_literal_expr() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SuspiciousMarkSafeUsage.into()
|
||||||
|
}
|
||||||
|
|
||||||
// URLOpen (`Request`)
|
// URLOpen (`Request`)
|
||||||
["urllib", "request", "Request"] | ["six", "moves", "urllib", "request", "Request"] => {
|
["urllib", "request", "Request"] | ["six", "moves", "urllib", "request", "Request"] => {
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,116 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
S308.py:5:12: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:6:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
4 | def some_func():
|
4 | def bad_func():
|
||||||
5 | return mark_safe('<script>alert("evil!")</script>')
|
5 | inject = "harmful_input"
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
6 | mark_safe(inject)
|
||||||
|
| ^^^^^^^^^^^^^^^^^ S308
|
||||||
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:8:1: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:7:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
5 | inject = "harmful_input"
|
||||||
|
6 | mark_safe(inject)
|
||||||
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:8:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
8 | @mark_safe
|
6 | mark_safe(inject)
|
||||||
| ^^^^^^^^^^ S308
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
9 | def some_func():
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
10 | return '<script>alert("evil!")</script>'
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
10 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:17:12: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:9:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
16 | def some_func():
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
17 | return mark_safe('<script>alert("evil!")</script>')
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
10 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:20:1: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:10:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
20 | @mark_safe
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
10 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
11 |
|
||||||
|
12 | def good_func():
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:16:1: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
16 | @mark_safe
|
||||||
| ^^^^^^^^^^ S308
|
| ^^^^^^^^^^ S308
|
||||||
21 | def some_func():
|
17 | def some_func():
|
||||||
22 | return '<script>alert("evil!")</script>'
|
18 | return '<script>alert("evil!")</script>'
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:26:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
24 | def bad_func():
|
||||||
|
25 | inject = "harmful_input"
|
||||||
|
26 | mark_safe(inject)
|
||||||
|
| ^^^^^^^^^^^^^^^^^ S308
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:27:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
25 | inject = "harmful_input"
|
||||||
|
26 | mark_safe(inject)
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:28:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
26 | mark_safe(inject)
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
30 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:29:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
30 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:30:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
30 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
31 |
|
||||||
|
32 | def good_func():
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:36:1: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
36 | @mark_safe
|
||||||
|
| ^^^^^^^^^^ S308
|
||||||
|
37 | def some_func():
|
||||||
|
38 | return '<script>alert("evil!")</script>'
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,132 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
|
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
|
||||||
---
|
---
|
||||||
S308.py:5:12: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:6:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
4 | def some_func():
|
4 | def bad_func():
|
||||||
5 | return mark_safe('<script>alert("evil!")</script>')
|
5 | inject = "harmful_input"
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
6 | mark_safe(inject)
|
||||||
|
| ^^^^^^^^^^^^^^^^^ S308
|
||||||
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:8:2: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:7:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
5 | inject = "harmful_input"
|
||||||
|
6 | mark_safe(inject)
|
||||||
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:8:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
8 | @mark_safe
|
6 | mark_safe(inject)
|
||||||
| ^^^^^^^^^ S308
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
9 | def some_func():
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
10 | return '<script>alert("evil!")</script>'
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
10 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:17:12: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:9:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
16 | def some_func():
|
7 | mark_safe("I will add" + inject + "to my string")
|
||||||
17 | return mark_safe('<script>alert("evil!")</script>')
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
10 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:20:2: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:10:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
20 | @mark_safe
|
8 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
9 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
10 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
11 |
|
||||||
|
12 | def good_func():
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:16:2: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
16 | @mark_safe
|
||||||
| ^^^^^^^^^ S308
|
| ^^^^^^^^^ S308
|
||||||
21 | def some_func():
|
17 | def some_func():
|
||||||
22 | return '<script>alert("evil!")</script>'
|
18 | return '<script>alert("evil!")</script>'
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:26:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:26:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
25 | # https://github.com/astral-sh/ruff/issues/15522
|
24 | def bad_func():
|
||||||
26 | map(mark_safe, [])
|
25 | inject = "harmful_input"
|
||||||
| ^^^^^^^^^ S308
|
26 | mark_safe(inject)
|
||||||
27 | foo = mark_safe
|
| ^^^^^^^^^^^^^^^^^ S308
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
|
|
|
||||||
|
|
||||||
S308.py:27:7: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
S308.py:27:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
|
||||||
25 | # https://github.com/astral-sh/ruff/issues/15522
|
25 | inject = "harmful_input"
|
||||||
26 | map(mark_safe, [])
|
26 | mark_safe(inject)
|
||||||
27 | foo = mark_safe
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:28:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
26 | mark_safe(inject)
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
30 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:29:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
27 | mark_safe("I will add" + inject + "to my string")
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
30 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:30:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
28 | mark_safe("I will add %s to my string" % inject)
|
||||||
|
29 | mark_safe("I will add {} to my string".format(inject))
|
||||||
|
30 | mark_safe(f"I will add {inject} to my string")
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S308
|
||||||
|
31 |
|
||||||
|
32 | def good_func():
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:36:2: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
36 | @mark_safe
|
||||||
|
| ^^^^^^^^^ S308
|
||||||
|
37 | def some_func():
|
||||||
|
38 | return '<script>alert("evil!")</script>'
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:42:5: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
41 | # https://github.com/astral-sh/ruff/issues/15522
|
||||||
|
42 | map(mark_safe, [])
|
||||||
|
| ^^^^^^^^^ S308
|
||||||
|
43 | foo = mark_safe
|
||||||
|
|
|
||||||
|
|
||||||
|
S308.py:43:7: S308 Use of `mark_safe` may expose cross-site scripting vulnerabilities
|
||||||
|
|
|
||||||
|
41 | # https://github.com/astral-sh/ruff/issues/15522
|
||||||
|
42 | map(mark_safe, [])
|
||||||
|
43 | foo = mark_safe
|
||||||
| ^^^^^^^^^ S308
|
| ^^^^^^^^^ S308
|
||||||
|
|
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue