Skip to content

Commit fce9f63

Browse files
authored
[flake8-bandit] Implement mako-templates (S702) (#8533)
See: #1646.
1 parent ce549e7 commit fce9f63

File tree

8 files changed

+102
-0
lines changed

8 files changed

+102
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from mako.template import Template
2+
from mako import template
3+
import mako
4+
5+
6+
Template("hello")
7+
8+
mako.template.Template("hern")
9+
template.Template("hern")

crates/ruff_linter/src/checkers/ast/analyze/expression.rs

+3
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
571571
if checker.enabled(Rule::Jinja2AutoescapeFalse) {
572572
flake8_bandit::rules::jinja2_autoescape_false(checker, call);
573573
}
574+
if checker.enabled(Rule::MakoTemplates) {
575+
flake8_bandit::rules::mako_templates(checker, call);
576+
}
574577
if checker.enabled(Rule::HardcodedPasswordFuncArg) {
575578
flake8_bandit::rules::hardcoded_password_func_arg(checker, keywords);
576579
}

crates/ruff_linter/src/codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
629629
(Flake8Bandit, "609") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnixCommandWildcardInjection),
630630
(Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen),
631631
(Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse),
632+
(Flake8Bandit, "702") => (RuleGroup::Preview, rules::flake8_bandit::rules::MakoTemplates),
632633

633634
// flake8-boolean-trap
634635
(Flake8BooleanTrap, "001") => (RuleGroup::Stable, rules::flake8_boolean_trap::rules::BooleanTypeHintPositionalArgument),

crates/ruff_linter/src/rules/flake8_bandit/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mod tests {
2828
#[test_case(Rule::HardcodedTempFile, Path::new("S108.py"))]
2929
#[test_case(Rule::HashlibInsecureHashFunction, Path::new("S324.py"))]
3030
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"))]
31+
#[test_case(Rule::MakoTemplates, Path::new("S702.py"))]
3132
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"))]
3233
#[test_case(Rule::ParamikoCall, Path::new("S601.py"))]
3334
#[test_case(Rule::RequestWithNoCertValidation, Path::new("S501.py"))]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use crate::checkers::ast::Checker;
2+
use ruff_diagnostics::{Diagnostic, Violation};
3+
use ruff_macros::{derive_message_formats, violation};
4+
use ruff_python_ast::{self as ast};
5+
use ruff_text_size::Ranged;
6+
7+
/// ## What it does
8+
/// Checks for uses of the `mako` templates.
9+
///
10+
/// ## Why is this bad?
11+
/// Mako templates allow HTML and JavaScript rendering by default, and are
12+
/// inherently open to XSS attacks. Ensure variables in all templates are
13+
/// properly sanitized via the `n`, `h` or `x` flags (depending on context).
14+
/// For example, to HTML escape the variable `data`, use `${ data |h }`.
15+
///
16+
/// ## Example
17+
/// ```python
18+
/// from mako.template import Template
19+
///
20+
/// Template("hello")
21+
/// ```
22+
///
23+
/// Use instead:
24+
/// ```python
25+
/// from mako.template import Template
26+
///
27+
/// Template("hello |h")
28+
/// ```
29+
///
30+
/// ## References
31+
/// - [Mako documentation](https://www.makotemplates.org/)
32+
/// - [OpenStack security: Cross site scripting XSS](https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html)
33+
/// - [Common Weakness Enumeration: CWE-80](https://cwe.mitre.org/data/definitions/80.html)
34+
#[violation]
35+
pub struct MakoTemplates;
36+
37+
impl Violation for MakoTemplates {
38+
#[derive_message_formats]
39+
fn message(&self) -> String {
40+
format!(
41+
"Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks"
42+
)
43+
}
44+
}
45+
46+
/// S702
47+
pub(crate) fn mako_templates(checker: &mut Checker, call: &ast::ExprCall) {
48+
if checker
49+
.semantic()
50+
.resolve_call_path(&call.func)
51+
.is_some_and(|call_path| matches!(call_path.as_slice(), ["mako", "template", "Template"]))
52+
{
53+
checker
54+
.diagnostics
55+
.push(Diagnostic::new(MakoTemplates, call.func.range()));
56+
}
57+
}

crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub(crate) use hardcoded_tmp_directory::*;
1111
pub(crate) use hashlib_insecure_hash_functions::*;
1212
pub(crate) use jinja2_autoescape_false::*;
1313
pub(crate) use logging_config_insecure_listen::*;
14+
pub(crate) use mako_templates::*;
1415
pub(crate) use paramiko_calls::*;
1516
pub(crate) use request_with_no_cert_validation::*;
1617
pub(crate) use request_without_timeout::*;
@@ -37,6 +38,7 @@ mod hardcoded_tmp_directory;
3738
mod hashlib_insecure_hash_functions;
3839
mod jinja2_autoescape_false;
3940
mod logging_config_insecure_listen;
41+
mod mako_templates;
4042
mod paramiko_calls;
4143
mod request_with_no_cert_validation;
4244
mod request_without_timeout;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
3+
---
4+
S702.py:6:1: S702 Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks
5+
|
6+
6 | Template("hello")
7+
| ^^^^^^^^ S702
8+
7 |
9+
8 | mako.template.Template("hern")
10+
|
11+
12+
S702.py:8:1: S702 Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks
13+
|
14+
6 | Template("hello")
15+
7 |
16+
8 | mako.template.Template("hern")
17+
| ^^^^^^^^^^^^^^^^^^^^^^ S702
18+
9 | template.Template("hern")
19+
|
20+
21+
S702.py:9:1: S702 Mako templates allow HTML and JavaScript rendering by default and are inherently open to XSS attacks
22+
|
23+
8 | mako.template.Template("hern")
24+
9 | template.Template("hern")
25+
| ^^^^^^^^^^^^^^^^^ S702
26+
|
27+
28+

ruff.schema.json

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)