From 8cf9d8fe2f71ff38c13ed912857985286c478f9a Mon Sep 17 00:00:00 2001 From: qdegraaf Date: Wed, 22 Nov 2023 18:21:31 +0100 Subject: [PATCH 1/7] Add boilerplate for S4XX rules, add fixtures --- .../test/fixtures/flake8_bandit/S401.py | 2 ++ .../test/fixtures/flake8_bandit/S402.py | 2 ++ .../test/fixtures/flake8_bandit/S403.py | 2 ++ .../test/fixtures/flake8_bandit/S404.py | 3 +++ .../test/fixtures/flake8_bandit/S405.py | 3 +++ .../test/fixtures/flake8_bandit/S406.py | 3 +++ .../test/fixtures/flake8_bandit/S407.py | 4 +++ .../test/fixtures/flake8_bandit/S408.py | 2 ++ .../test/fixtures/flake8_bandit/S409.py | 2 ++ .../test/fixtures/flake8_bandit/S410.py | 2 ++ .../test/fixtures/flake8_bandit/S411.py | 2 ++ .../test/fixtures/flake8_bandit/S412.py | 3 +++ .../test/fixtures/flake8_bandit/S413.py | 6 +++++ .../src/rules/flake8_bandit/rules/mod.rs | 1 + .../flake8_bandit/rules/suspicious_imports.rs | 27 +++++++++++++++++++ 15 files changed, 64 insertions(+) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S401.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S402.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S404.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S406.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S408.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S409.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S411.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S401.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S401.py new file mode 100644 index 0000000000000..1140e955ac39d --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S401.py @@ -0,0 +1,2 @@ +import telnetlib # S401 +from telnetlib import Telnet # S401 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S402.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S402.py new file mode 100644 index 0000000000000..f58a56259bc67 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S402.py @@ -0,0 +1,2 @@ +import ftplib # S402 +from ftplib import FTP # S402 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py new file mode 100644 index 0000000000000..2845962802178 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py @@ -0,0 +1,2 @@ +import dill # S403 +from dill import objects # S403 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S404.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S404.py new file mode 100644 index 0000000000000..31de131180f4a --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S404.py @@ -0,0 +1,3 @@ +import subprocess # S404 +from subprocess import Popen # S404 +from subprocess import Popen as pop # S404 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py new file mode 100644 index 0000000000000..b6f5f90e56434 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py @@ -0,0 +1,3 @@ +from xml import etree # S405 +import xml.etree as xmle # S405 +import xml.etree # S405 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S406.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S406.py new file mode 100644 index 0000000000000..698bc6e75ba43 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S406.py @@ -0,0 +1,3 @@ +from xml import sax # S406 +import xml.sax as xmls # S406 +import xml.sax # S406 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py new file mode 100644 index 0000000000000..2b6363b4e7041 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py @@ -0,0 +1,4 @@ +from xml.dom import expatbuilder # S407 +from xml.sax import expatreader # S407 +import xml.dom.expatbuilder # S407 +import xml.sax.expatreader # S407 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S408.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S408.py new file mode 100644 index 0000000000000..5fa6fb8e7f5c1 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S408.py @@ -0,0 +1,2 @@ +from xml.dom.minidom import parseString # S408 +import xml.dom.minidom # S408 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S409.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S409.py new file mode 100644 index 0000000000000..fe9ea30d1bf82 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S409.py @@ -0,0 +1,2 @@ +from xml.dom.pulldom import parseString # S409 +import xml.dom.pulldom # S409 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py new file mode 100644 index 0000000000000..07182c1a7c05a --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py @@ -0,0 +1,2 @@ +import lxml # S410 +from lxml import etree # S410 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S411.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S411.py new file mode 100644 index 0000000000000..b72b6520fbbef --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S411.py @@ -0,0 +1,2 @@ +import xmlrpc # S411 +from xmlrpc import server # S411 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py new file mode 100644 index 0000000000000..036f9930c4fe2 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py @@ -0,0 +1,3 @@ +import wsgiref.handlers # S413 +from twisted.internet import reactor # S413 +from twisted.web import static, server, twcgi # S413 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py new file mode 100644 index 0000000000000..a09a4b41c8089 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py @@ -0,0 +1,6 @@ +from cryptography.hazmat import backends # S413 +from cryptography.hazmat.primitives.asymmetric import dsa # S413 +from cryptography.hazmat.primitives.asymmetric import ec # S413 +from cryptography.hazmat.primitives.asymmetric import rsa # S413 +from Crypto.PublicKey import RSA as pycrypto_rsa # S413 +from Cryptodome.PublicKey import DSA as pycryptodomex_dsa # S413 diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs index ee1de347d6152..1648932daf1ab 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs @@ -55,3 +55,4 @@ mod try_except_continue; mod try_except_pass; mod unsafe_yaml_load; mod weak_cryptographic_key; +mod suspicious_imports; diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs new file mode 100644 index 0000000000000..2410ffe6c12e5 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -0,0 +1,27 @@ +//! Check for imports of or from suspicious modules. +//! +//! See: +use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, Expr, ExprCall, Stmt}; +use ruff_text_size::Ranged; + +use crate::checkers::ast::Checker; +use crate::registry::AsRule; + +// TODO: Violations and Docs + +/// S401.py, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413 +pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { + let Some(diagnostic_kind) = match stmt { + // TODO: Implementation + Stmt::Import(ast::StmtImport { names, range: _ }) => {}, + Stmt::ImportFrom(ast::StmtImport { names, range: _ }) => {}, + _ => panic!("Expected Stmt::Import | Stmt::ImportFrom") + }; + + let diagnostic = Diagnostic::new::(diagnostic_kind, stmt.range()); + if checker.enabled(diagnostic.kind.rule()) { + checker.diagnostics.push(diagnostic); + } +} From d6061185480e97a2229717345ded1d1fc9624e3d Mon Sep 17 00:00:00 2001 From: qdegraaf Date: Fri, 24 Nov 2023 12:16:06 +0100 Subject: [PATCH 2/7] Add first test, update schema, add first check --- .../src/checkers/ast/analyze/statement.rs | 6 + crates/ruff_linter/src/codes.rs | 14 ++ .../src/rules/flake8_bandit/mod.rs | 1 + .../src/rules/flake8_bandit/rules/mod.rs | 3 +- .../flake8_bandit/rules/suspicious_imports.rs | 178 ++++++++++++++++-- ruff.schema.json | 17 ++ 6 files changed, 206 insertions(+), 13 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 20ed78c8350f5..ad15499ad4afa 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -552,6 +552,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::DeprecatedMockImport) { pyupgrade::rules::deprecated_mock_import(checker, stmt); } + if checker.enabled(Rule::SuspiciousTelnetlibImport) { + flake8_bandit::rules::suspicious_imports(checker, stmt) + } for alias in names { if checker.enabled(Rule::NonAsciiImportName) { @@ -751,6 +754,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pyupgrade::rules::unnecessary_builtin_import(checker, stmt, module, names); } } + if checker.enabled(Rule::SuspiciousTelnetlibImport) { + flake8_bandit::rules::suspicious_imports(checker, stmt) + } if checker.enabled(Rule::BannedApi) { if let Some(module) = helpers::resolve_imported_module_path(level, module, checker.module_path) diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 75f4d29673462..11cdca4948f58 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -625,6 +625,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Bandit, "321") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousFTPLibUsage), (Flake8Bandit, "323") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousUnverifiedContextUsage), (Flake8Bandit, "324") => (RuleGroup::Stable, rules::flake8_bandit::rules::HashlibInsecureHashFunction), + (Flake8Bandit, "401") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousTelnetlibImport), + (Flake8Bandit, "402") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousFtplibImport), + (Flake8Bandit, "403") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPickleImport), + (Flake8Bandit, "404") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousSubprocessImport), + (Flake8Bandit, "405") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlEtreeImport), + (Flake8Bandit, "406") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlSaxImport), + (Flake8Bandit, "407") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlExpatImport), + (Flake8Bandit, "408") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlMinidomImport), + (Flake8Bandit, "409") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlPulldomImport), + (Flake8Bandit, "410") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousLxmlImport), + (Flake8Bandit, "411") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlrpclibImport), + (Flake8Bandit, "412") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousHttpoxyImport), + (Flake8Bandit, "413") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPycryptoImport), + (Flake8Bandit, "415") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPyghmiImport), (Flake8Bandit, "501") => (RuleGroup::Stable, rules::flake8_bandit::rules::RequestWithNoCertValidation), (Flake8Bandit, "505") => (RuleGroup::Preview, rules::flake8_bandit::rules::WeakCryptographicKey), (Flake8Bandit, "506") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnsafeYAMLLoad), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index ce041669f1782..3a00b21e02f4f 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -45,6 +45,7 @@ mod tests { #[test_case(Rule::SuspiciousEvalUsage, Path::new("S307.py"))] #[test_case(Rule::SuspiciousURLOpenUsage, Path::new("S310.py"))] #[test_case(Rule::SuspiciousTelnetUsage, Path::new("S312.py"))] + #[test_case(Rule::SuspiciousTelnetlibImport, Path::new("S401.py"))] #[test_case(Rule::TryExceptContinue, Path::new("S112.py"))] #[test_case(Rule::TryExceptPass, Path::new("S110.py"))] #[test_case(Rule::UnixCommandWildcardInjection, Path::new("S609.py"))] diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs index 1648932daf1ab..e33ee02f098c9 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/mod.rs @@ -21,6 +21,7 @@ pub(crate) use snmp_insecure_version::*; pub(crate) use snmp_weak_cryptography::*; pub(crate) use ssh_no_host_key_verification::*; pub(crate) use suspicious_function_call::*; +pub(crate) use suspicious_imports::*; pub(crate) use tarfile_unsafe_members::*; pub(crate) use try_except_continue::*; pub(crate) use try_except_pass::*; @@ -50,9 +51,9 @@ mod snmp_insecure_version; mod snmp_weak_cryptography; mod ssh_no_host_key_verification; mod suspicious_function_call; +mod suspicious_imports; mod tarfile_unsafe_members; mod try_except_continue; mod try_except_pass; mod unsafe_yaml_load; mod weak_cryptographic_key; -mod suspicious_imports; diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs index 2410ffe6c12e5..0c908d5f65dcb 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -7,21 +7,175 @@ use ruff_python_ast::{self as ast, Expr, ExprCall, Stmt}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; +use crate::codes::Rule::SuspiciousFTPLibUsage; use crate::registry::AsRule; -// TODO: Violations and Docs +// TODO: Docs +// ref: https://github.com/PyCQA/bandit/blob/6b2e24722bdcc40ea37c3bc155b6856961763814/bandit/blacklists/imports.py#L17 +#[violation] +pub struct SuspiciousTelnetlibImport; -/// S401.py, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413 -pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { - let Some(diagnostic_kind) = match stmt { - // TODO: Implementation - Stmt::Import(ast::StmtImport { names, range: _ }) => {}, - Stmt::ImportFrom(ast::StmtImport { names, range: _ }) => {}, - _ => panic!("Expected Stmt::Import | Stmt::ImportFrom") - }; +impl Violation for SuspiciousTelnetlibImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`telnetlib` and related modules are considered insecure. Use SSH or some other encrypted protocol") + } +} + +#[violation] +pub struct SuspiciousFtplibImport; + +impl Violation for SuspiciousFtplibImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`ftplib` and related modules are considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol") + } +} + +#[violation] +pub struct SuspiciousPickleImport; + +impl Violation for SuspiciousPickleImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure") + } +} + +#[violation] +pub struct SuspiciousSubprocessImport; + +impl Violation for SuspiciousSubprocessImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`subprocess` module is possibly insecure") + } +} + +#[violation] +pub struct SuspiciousXmlEtreeImport; + +impl Violation for SuspiciousXmlEtreeImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.etree` methods are vulnerable to XML attacks") + } +} + +#[violation] +pub struct SuspiciousXmlSaxImport; + +impl Violation for SuspiciousXmlSaxImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.sax` methods are vulnerable to XML attacks") + } +} + +#[violation] +pub struct SuspiciousXmlExpatImport; + +impl Violation for SuspiciousXmlExpatImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.dom.expatbuilder` is vulnerable to XML attacks") + } +} - let diagnostic = Diagnostic::new::(diagnostic_kind, stmt.range()); - if checker.enabled(diagnostic.kind.rule()) { - checker.diagnostics.push(diagnostic); +#[violation] +pub struct SuspiciousXmlMinidomImport; + +impl Violation for SuspiciousXmlMinidomImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.dom.minidom` is vulnerable to XML attacks") + } +} + +#[violation] +pub struct SuspiciousXmlPulldomImport; + +impl Violation for SuspiciousXmlPulldomImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.dom.pulldom` is vulnerable to XML attacks") + } +} + +#[violation] +pub struct SuspiciousLxmlImport; + +impl Violation for SuspiciousLxmlImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`lxml` is vulnerable to XML attacks") + } +} + +#[violation] +pub struct SuspiciousXmlrpclibImport; + +impl Violation for SuspiciousXmlrpclibImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("XMLRPC is particularly dangerous as it is also concerned with communicating data over a network") + } +} + +#[violation] +pub struct SuspiciousHttpoxyImport; + +impl Violation for SuspiciousHttpoxyImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`httpoxy` is a set of vulnerabilities that affect application code running inCGI, or CGI-like environments. The use of CGI for web applications should be avoided") + } +} + +#[violation] +pub struct SuspiciousPycryptoImport; + +impl Violation for SuspiciousPycryptoImport { + #[derive_message_formats] + fn message(&self) -> String { + format!( + "`pycrypto` library is known to have publicly disclosed buffer overflow vulnerability" + ) } } + +#[violation] +pub struct SuspiciousPyghmiImport; + +impl Violation for SuspiciousPyghmiImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol") + } +} + +/// S401, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413 +pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { + match stmt { + Stmt::Import(ast::StmtImport { names, ..}) => { + for name in names { + match name.name.as_str() { + "telnetlib" => { + checker.diagnostics.push(Diagnostic::new(SuspiciousTelnetlibImport, name.range)) + }, + _ => {} + } + } + }, + Stmt::ImportFrom(ast::StmtImportFrom { module, .. }) => { + let Some(identifier) = module else { return }; + match identifier.as_str() { + "telnetlib" => { + checker.diagnostics.push(Diagnostic::new(SuspiciousTelnetlibImport, identifier.range())) + }, + _ => {} + } + }, + _ => panic!("Expected Stmt::Import | Stmt::ImportFrom"), + }; +} \ No newline at end of file diff --git a/ruff.schema.json b/ruff.schema.json index c50d2e69df672..ffbe165469f93 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3486,6 +3486,23 @@ "S321", "S323", "S324", + "S4", + "S40", + "S401", + "S402", + "S403", + "S404", + "S405", + "S406", + "S407", + "S408", + "S409", + "S41", + "S410", + "S411", + "S412", + "S413", + "S415", "S5", "S50", "S501", From 8f0fae513c002201ffa99bc315f2c193da3ce5af Mon Sep 17 00:00:00 2001 From: qdegraaf Date: Fri, 24 Nov 2023 14:34:46 +0100 Subject: [PATCH 3/7] Add module level import rules --- .../test/fixtures/flake8_bandit/S403.py | 6 ++ .../test/fixtures/flake8_bandit/S410.py | 2 +- .../test/fixtures/flake8_bandit/S412.py | 6 +- .../test/fixtures/flake8_bandit/S415.py | 3 + .../src/checkers/ast/analyze/statement.rs | 24 ++++- .../src/rules/flake8_bandit/mod.rs | 6 ++ .../flake8_bandit/rules/suspicious_imports.rs | 100 +++++++++++++++--- ...s__flake8_bandit__tests__S401_S401.py.snap | 18 ++++ ...s__flake8_bandit__tests__S402_S402.py.snap | 18 ++++ ...s__flake8_bandit__tests__S403_S403.py.snap | 78 ++++++++++++++ ...s__flake8_bandit__tests__S404_S404.py.snap | 28 +++++ ...s__flake8_bandit__tests__S410_S410.py.snap | 18 ++++ ...s__flake8_bandit__tests__S411_S411.py.snap | 18 ++++ ...s__flake8_bandit__tests__S415_S415.py.snap | 18 ++++ 14 files changed, 322 insertions(+), 21 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/flake8_bandit/S415.py create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S404_S404.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S410_S410.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py index 2845962802178..2aec54eb8c936 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py @@ -1,2 +1,8 @@ import dill # S403 from dill import objects # S403 +import shelve +from shelve import open +import cPickle +from cPickle import load +import pickle +from pickle import load diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py index 07182c1a7c05a..5ff308d53d35a 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py @@ -1,2 +1,2 @@ import lxml # S410 -from lxml import etree # S410 +from lxml import etree # S410 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py index 036f9930c4fe2..5728162557ce7 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py @@ -1,3 +1,3 @@ -import wsgiref.handlers # S413 -from twisted.internet import reactor # S413 -from twisted.web import static, server, twcgi # S413 +import wsgiref.handlers # S412 +from twisted.internet import reactor # S412 +from twisted.web import static, server, twcgi # S412 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S415.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S415.py new file mode 100644 index 0000000000000..4c9a5c267e2aa --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S415.py @@ -0,0 +1,3 @@ +import pyghmi # S415 +from pyghmi import foo # S415 + diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index ad15499ad4afa..4956211d43e83 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -552,8 +552,16 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::DeprecatedMockImport) { pyupgrade::rules::deprecated_mock_import(checker, stmt); } - if checker.enabled(Rule::SuspiciousTelnetlibImport) { - flake8_bandit::rules::suspicious_imports(checker, stmt) + if checker.any_enabled(&[ + Rule::SuspiciousTelnetlibImport, + Rule::SuspiciousFtplibImport, + Rule::SuspiciousPickleImport, + Rule::SuspiciousSubprocessImport, + Rule::SuspiciousLxmlImport, + Rule::SuspiciousXmlrpclibImport, + Rule::SuspiciousPyghmiImport, + ]) { + flake8_bandit::rules::suspicious_imports(checker, stmt); } for alias in names { @@ -754,8 +762,16 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pyupgrade::rules::unnecessary_builtin_import(checker, stmt, module, names); } } - if checker.enabled(Rule::SuspiciousTelnetlibImport) { - flake8_bandit::rules::suspicious_imports(checker, stmt) + if checker.any_enabled(&[ + Rule::SuspiciousTelnetlibImport, + Rule::SuspiciousFtplibImport, + Rule::SuspiciousPickleImport, + Rule::SuspiciousSubprocessImport, + Rule::SuspiciousLxmlImport, + Rule::SuspiciousXmlrpclibImport, + Rule::SuspiciousPyghmiImport, + ]) { + flake8_bandit::rules::suspicious_imports(checker, stmt); } if checker.enabled(Rule::BannedApi) { if let Some(module) = diff --git a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index 3a00b21e02f4f..ba434a441ccc6 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -46,6 +46,12 @@ mod tests { #[test_case(Rule::SuspiciousURLOpenUsage, Path::new("S310.py"))] #[test_case(Rule::SuspiciousTelnetUsage, Path::new("S312.py"))] #[test_case(Rule::SuspiciousTelnetlibImport, Path::new("S401.py"))] + #[test_case(Rule::SuspiciousFtplibImport, Path::new("S402.py"))] + #[test_case(Rule::SuspiciousPickleImport, Path::new("S403.py"))] + #[test_case(Rule::SuspiciousSubprocessImport, Path::new("S404.py"))] + #[test_case(Rule::SuspiciousLxmlImport, Path::new("S410.py"))] + #[test_case(Rule::SuspiciousXmlrpclibImport, Path::new("S411.py"))] + #[test_case(Rule::SuspiciousPyghmiImport, Path::new("S415.py"))] #[test_case(Rule::TryExceptContinue, Path::new("S112.py"))] #[test_case(Rule::TryExceptPass, Path::new("S110.py"))] #[test_case(Rule::UnixCommandWildcardInjection, Path::new("S609.py"))] diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs index 0c908d5f65dcb..aea67f7b956bb 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -3,11 +3,10 @@ //! See: use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr, ExprCall, Stmt}; -use ruff_text_size::Ranged; +use ruff_python_ast::{self as ast, Stmt}; +use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; -use crate::codes::Rule::SuspiciousFTPLibUsage; use crate::registry::AsRule; // TODO: Docs @@ -157,25 +156,100 @@ impl Violation for SuspiciousPyghmiImport { /// S401, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413 pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { match stmt { - Stmt::Import(ast::StmtImport { names, ..}) => { + Stmt::Import(ast::StmtImport { names, .. }) => { for name in names { match name.name.as_str() { - "telnetlib" => { - checker.diagnostics.push(Diagnostic::new(SuspiciousTelnetlibImport, name.range)) - }, + "telnetlib" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousTelnetlibImport), + name.range, + ), + "ftplib" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousFtplibImport), + name.range, + ), + "pickle" | "cPickle" | "dill" | "shelve" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPickleImport), + name.range, + ), + "subprocess" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousSubprocessImport), + name.range, + ), + "lxml" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousLxmlImport), + name.range, + ), + "xmlrpc" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlrpclibImport), + name.range, + ), + "pyghmi" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPyghmiImport), + name.range, + ), _ => {} } } - }, + } Stmt::ImportFrom(ast::StmtImportFrom { module, .. }) => { let Some(identifier) = module else { return }; match identifier.as_str() { - "telnetlib" => { - checker.diagnostics.push(Diagnostic::new(SuspiciousTelnetlibImport, identifier.range())) - }, + "telnetlib" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousTelnetlibImport), + identifier.range(), + ), + "ftplib" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousFtplibImport), + identifier.range(), + ), + "pickle" | "cPickle" | "dill" | "shelve" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPickleImport), + identifier.range(), + ), + "subprocess" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousSubprocessImport), + identifier.range(), + ), + "lxml" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousLxmlImport), + identifier.range(), + ), + "xmlrpc" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlrpclibImport), + identifier.range(), + ), + "pyghmi" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPyghmiImport), + identifier.range(), + ), _ => {} } - }, + } _ => panic!("Expected Stmt::Import | Stmt::ImportFrom"), }; -} \ No newline at end of file +} + +fn check_and_push_diagnostic( + checker: &mut Checker, + diagnostic_kind: DiagnosticKind, + range: TextRange, +) { + let diagnostic = Diagnostic::new::(diagnostic_kind, range); + if checker.enabled(diagnostic.kind.rule()) { + checker.diagnostics.push(diagnostic); + } +} diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap new file mode 100644 index 0000000000000..e886364f594b2 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S401.py:1:8: S401 `telnetlib` and related modules are considered insecure. Use SSH or some other encrypted protocol + | +1 | import telnetlib # S401 + | ^^^^^^^^^ S401 +2 | from telnetlib import Telnet # S401 + | + +S401.py:2:6: S401 `telnetlib` and related modules are considered insecure. Use SSH or some other encrypted protocol + | +1 | import telnetlib # S401 +2 | from telnetlib import Telnet # S401 + | ^^^^^^^^^ S401 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap new file mode 100644 index 0000000000000..a61b13c07a886 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S402.py:1:8: S402 `ftplib` and related modules are considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol + | +1 | import ftplib # S402 + | ^^^^^^ S402 +2 | from ftplib import FTP # S402 + | + +S402.py:2:6: S402 `ftplib` and related modules are considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol + | +1 | import ftplib # S402 +2 | from ftplib import FTP # S402 + | ^^^^^^ S402 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap new file mode 100644 index 0000000000000..2933b0436e96f --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap @@ -0,0 +1,78 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S403.py:1:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +1 | import dill # S403 + | ^^^^ S403 +2 | from dill import objects # S403 +3 | import shelve + | + +S403.py:2:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +1 | import dill # S403 +2 | from dill import objects # S403 + | ^^^^ S403 +3 | import shelve +4 | from shelve import open + | + +S403.py:3:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +1 | import dill # S403 +2 | from dill import objects # S403 +3 | import shelve + | ^^^^^^ S403 +4 | from shelve import open +5 | import cPickle + | + +S403.py:4:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +2 | from dill import objects # S403 +3 | import shelve +4 | from shelve import open + | ^^^^^^ S403 +5 | import cPickle +6 | from cPickle import load + | + +S403.py:5:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +3 | import shelve +4 | from shelve import open +5 | import cPickle + | ^^^^^^^ S403 +6 | from cPickle import load +7 | import pickle + | + +S403.py:6:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +4 | from shelve import open +5 | import cPickle +6 | from cPickle import load + | ^^^^^^^ S403 +7 | import pickle +8 | from pickle import load + | + +S403.py:7:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +5 | import cPickle +6 | from cPickle import load +7 | import pickle + | ^^^^^^ S403 +8 | from pickle import load + | + +S403.py:8:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure + | +6 | from cPickle import load +7 | import pickle +8 | from pickle import load + | ^^^^^^ S403 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S404_S404.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S404_S404.py.snap new file mode 100644 index 0000000000000..f67e404f427e4 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S404_S404.py.snap @@ -0,0 +1,28 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S404.py:1:8: S404 `subprocess` module is possibly insecure + | +1 | import subprocess # S404 + | ^^^^^^^^^^ S404 +2 | from subprocess import Popen # S404 +3 | from subprocess import Popen as pop # S404 + | + +S404.py:2:6: S404 `subprocess` module is possibly insecure + | +1 | import subprocess # S404 +2 | from subprocess import Popen # S404 + | ^^^^^^^^^^ S404 +3 | from subprocess import Popen as pop # S404 + | + +S404.py:3:6: S404 `subprocess` module is possibly insecure + | +1 | import subprocess # S404 +2 | from subprocess import Popen # S404 +3 | from subprocess import Popen as pop # S404 + | ^^^^^^^^^^ S404 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S410_S410.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S410_S410.py.snap new file mode 100644 index 0000000000000..56304d26707e0 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S410_S410.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S410.py:1:8: S410 `lxml` is vulnerable to XML attacks + | +1 | import lxml # S410 + | ^^^^ S410 +2 | from lxml import etree # S410 + | + +S410.py:2:6: S410 `lxml` is vulnerable to XML attacks + | +1 | import lxml # S410 +2 | from lxml import etree # S410 + | ^^^^ S410 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap new file mode 100644 index 0000000000000..09948c33ab82d --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S411.py:1:8: S411 XMLRPC is particularly dangerous as it is also concerned with communicating data over a network + | +1 | import xmlrpc # S411 + | ^^^^^^ S411 +2 | from xmlrpc import server # S411 + | + +S411.py:2:6: S411 XMLRPC is particularly dangerous as it is also concerned with communicating data over a network + | +1 | import xmlrpc # S411 +2 | from xmlrpc import server # S411 + | ^^^^^^ S411 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap new file mode 100644 index 0000000000000..af87b7c06dbfa --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S415.py:1:8: S415 An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol + | +1 | import pyghmi # S415 + | ^^^^^^ S415 +2 | from pyghmi import foo # S415 + | + +S415.py:2:6: S415 An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol + | +1 | import pyghmi # S415 +2 | from pyghmi import foo # S415 + | ^^^^^^ S415 + | + + From 5292b86ca1562241ba95df4c06e07e4d007a7789 Mon Sep 17 00:00:00 2001 From: qdegraaf Date: Fri, 24 Nov 2023 17:15:34 +0100 Subject: [PATCH 4/7] Add remaining checks, refine tests based on bandit spec --- .../test/fixtures/flake8_bandit/S405.py | 7 +- .../test/fixtures/flake8_bandit/S407.py | 2 - .../test/fixtures/flake8_bandit/S412.py | 4 +- .../test/fixtures/flake8_bandit/S413.py | 10 +- .../src/checkers/ast/analyze/statement.rs | 18 +- crates/ruff_linter/src/codes.rs | 2 +- .../src/rules/flake8_bandit/mod.rs | 9 +- .../flake8_bandit/rules/suspicious_imports.rs | 167 +++++++++++++++++- ...s__flake8_bandit__tests__S405_S405.py.snap | 38 ++++ ...s__flake8_bandit__tests__S406_S406.py.snap | 28 +++ ...s__flake8_bandit__tests__S407_S407.py.snap | 18 ++ ...s__flake8_bandit__tests__S408_S408.py.snap | 18 ++ ...s__flake8_bandit__tests__S409_S409.py.snap | 18 ++ ...s__flake8_bandit__tests__S412_S412.py.snap | 10 ++ ...s__flake8_bandit__tests__S413_S413.py.snap | 38 ++++ 15 files changed, 363 insertions(+), 24 deletions(-) create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S405_S405.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S406_S406.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S407_S407.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S408_S408.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S409_S409.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S412_S412.py.snap create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S413_S413.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py index b6f5f90e56434..8bf2d4a63b184 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py @@ -1,3 +1,4 @@ -from xml import etree # S405 -import xml.etree as xmle # S405 -import xml.etree # S405 +import xml.etree.cElementTree # S405 +from xml.etree import cElementTree # S405 +import xml.etree.ElementTree # S405 +from xml.etree import ElementTree # S405 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py index 2b6363b4e7041..e7d3841382f4c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py @@ -1,4 +1,2 @@ from xml.dom import expatbuilder # S407 -from xml.sax import expatreader # S407 import xml.dom.expatbuilder # S407 -import xml.sax.expatreader # S407 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py index 5728162557ce7..1b8163323ab93 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py @@ -1,3 +1 @@ -import wsgiref.handlers # S412 -from twisted.internet import reactor # S412 -from twisted.web import static, server, twcgi # S412 +from twisted.web.twcgi import CGIScript # S412 diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py index a09a4b41c8089..b0ec780ca8033 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py @@ -1,6 +1,4 @@ -from cryptography.hazmat import backends # S413 -from cryptography.hazmat.primitives.asymmetric import dsa # S413 -from cryptography.hazmat.primitives.asymmetric import ec # S413 -from cryptography.hazmat.primitives.asymmetric import rsa # S413 -from Crypto.PublicKey import RSA as pycrypto_rsa # S413 -from Cryptodome.PublicKey import DSA as pycryptodomex_dsa # S413 +import Crypto.Hash # S413 +from Crypto.Hash import MD2 # S413 +import Crypto.PublicKey # S413 +from Crypto.PublicKey import RSA # S413 diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 4956211d43e83..4c5360beb250e 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -557,8 +557,15 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { Rule::SuspiciousFtplibImport, Rule::SuspiciousPickleImport, Rule::SuspiciousSubprocessImport, + Rule::SuspiciousXmlEtreeImport, + Rule::SuspiciousXmlSaxImport, + Rule::SuspiciousXmlExpatImport, + Rule::SuspiciousXmlMinidomImport, + Rule::SuspiciousXmlPulldomImport, Rule::SuspiciousLxmlImport, - Rule::SuspiciousXmlrpclibImport, + Rule::SuspiciousXmlrpcImport, + Rule::SuspiciousHttpoxyImport, + Rule::SuspiciousPycryptoImport, Rule::SuspiciousPyghmiImport, ]) { flake8_bandit::rules::suspicious_imports(checker, stmt); @@ -767,8 +774,15 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { Rule::SuspiciousFtplibImport, Rule::SuspiciousPickleImport, Rule::SuspiciousSubprocessImport, + Rule::SuspiciousXmlEtreeImport, + Rule::SuspiciousXmlSaxImport, + Rule::SuspiciousXmlExpatImport, + Rule::SuspiciousXmlMinidomImport, + Rule::SuspiciousXmlPulldomImport, Rule::SuspiciousLxmlImport, - Rule::SuspiciousXmlrpclibImport, + Rule::SuspiciousXmlrpcImport, + Rule::SuspiciousHttpoxyImport, + Rule::SuspiciousPycryptoImport, Rule::SuspiciousPyghmiImport, ]) { flake8_bandit::rules::suspicious_imports(checker, stmt); diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 11cdca4948f58..b7474e70ffb0c 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -635,7 +635,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Bandit, "408") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlMinidomImport), (Flake8Bandit, "409") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlPulldomImport), (Flake8Bandit, "410") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousLxmlImport), - (Flake8Bandit, "411") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlrpclibImport), + (Flake8Bandit, "411") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlrpcImport), (Flake8Bandit, "412") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousHttpoxyImport), (Flake8Bandit, "413") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPycryptoImport), (Flake8Bandit, "415") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPyghmiImport), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index ba434a441ccc6..a27f8b19444d8 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -49,8 +49,15 @@ mod tests { #[test_case(Rule::SuspiciousFtplibImport, Path::new("S402.py"))] #[test_case(Rule::SuspiciousPickleImport, Path::new("S403.py"))] #[test_case(Rule::SuspiciousSubprocessImport, Path::new("S404.py"))] + #[test_case(Rule::SuspiciousXmlEtreeImport, Path::new("S405.py"))] + #[test_case(Rule::SuspiciousXmlSaxImport, Path::new("S406.py"))] + #[test_case(Rule::SuspiciousXmlExpatImport, Path::new("S407.py"))] + #[test_case(Rule::SuspiciousXmlMinidomImport, Path::new("S408.py"))] + #[test_case(Rule::SuspiciousXmlPulldomImport, Path::new("S409.py"))] #[test_case(Rule::SuspiciousLxmlImport, Path::new("S410.py"))] - #[test_case(Rule::SuspiciousXmlrpclibImport, Path::new("S411.py"))] + #[test_case(Rule::SuspiciousXmlrpcImport, Path::new("S411.py"))] + #[test_case(Rule::SuspiciousHttpoxyImport, Path::new("S412.py"))] + #[test_case(Rule::SuspiciousPycryptoImport, Path::new("S413.py"))] #[test_case(Rule::SuspiciousPyghmiImport, Path::new("S415.py"))] #[test_case(Rule::TryExceptContinue, Path::new("S112.py"))] #[test_case(Rule::TryExceptPass, Path::new("S110.py"))] diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs index aea67f7b956bb..a8904abf2c5d5 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -112,9 +112,9 @@ impl Violation for SuspiciousLxmlImport { } #[violation] -pub struct SuspiciousXmlrpclibImport; +pub struct SuspiciousXmlrpcImport; -impl Violation for SuspiciousXmlrpclibImport { +impl Violation for SuspiciousXmlrpcImport { #[derive_message_formats] fn message(&self) -> String { format!("XMLRPC is particularly dangerous as it is also concerned with communicating data over a network") @@ -153,7 +153,7 @@ impl Violation for SuspiciousPyghmiImport { } } -/// S401, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413 +/// S401, S402, S403, S404, S405, S406, S407, S408, S409, S410, S411, S412, S413, S415 pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { match stmt { Stmt::Import(ast::StmtImport { names, .. }) => { @@ -179,6 +179,33 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { DiagnosticKind::from(SuspiciousSubprocessImport), name.range, ), + "xml.etree.cElementTree" | "xml.etree.ElementTree" => { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlEtreeImport), + name.range, + ); + } + "xml.sax" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlSaxImport), + name.range, + ), + "xml.dom.expatbuilder" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlExpatImport), + name.range, + ), + "xml.dom.minidom" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlMinidomImport), + name.range, + ), + "xml.dom.pulldom" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlPulldomImport), + name.range, + ), "lxml" => check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousLxmlImport), @@ -186,9 +213,17 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { ), "xmlrpc" => check_and_push_diagnostic( checker, - DiagnosticKind::from(SuspiciousXmlrpclibImport), + DiagnosticKind::from(SuspiciousXmlrpcImport), name.range, ), + "Crypto.Cipher" | "Crypto.Hash" | "Crypto.IO" | "Crypto.Protocol" + | "Crypto.PublicKey" | "Crypto.Random" | "Crypto.Signature" | "Crypto.Util" => { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPycryptoImport), + name.range, + ); + } "pyghmi" => check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousPyghmiImport), @@ -198,7 +233,7 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { } } } - Stmt::ImportFrom(ast::StmtImportFrom { module, .. }) => { + Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. }) => { let Some(identifier) = module else { return }; match identifier.as_str() { "telnetlib" => check_and_push_diagnostic( @@ -221,6 +256,77 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { DiagnosticKind::from(SuspiciousSubprocessImport), identifier.range(), ), + "xml.etree" => { + for name in names { + if &name.name == "cElementTree" || &name.name == "ElementTree" { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlEtreeImport), + identifier.range(), + ); + } + } + } + "xml.etree.cElementTree" | "xml.etree.ElementTree" => { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlEtreeImport), + identifier.range(), + ); + } + "xml" => { + for name in names { + if &name.name == "sax" { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlSaxImport), + identifier.range(), + ); + } + } + } + "xml.sax" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlSaxImport), + identifier.range(), + ), + "xml.dom" => { + for name in names { + match name.name.as_str() { + "expatbuilder" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlExpatImport), + identifier.range(), + ), + "minidom" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlMinidomImport), + identifier.range(), + ), + "pulldom" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlPulldomImport), + identifier.range(), + ), + _ => (), + } + } + } + "xml.dom.expatbuilder" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlExpatImport), + identifier.range(), + ), + "xml.dom.minidom" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlMinidomImport), + identifier.range(), + ), + "xml.dom.pulldom" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlPulldomImport), + identifier.range(), + ), "lxml" => check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousLxmlImport), @@ -228,9 +334,58 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { ), "xmlrpc" => check_and_push_diagnostic( checker, - DiagnosticKind::from(SuspiciousXmlrpclibImport), + DiagnosticKind::from(SuspiciousXmlrpcImport), identifier.range(), ), + "wsgiref.handlers" => { + for name in names { + if &name.name == "CGIHandler" { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousHttpoxyImport), + identifier.range(), + ); + } + } + } + "twisted.web.twcgi" => { + for name in names { + if &name.name == "CGIScript" { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousHttpoxyImport), + identifier.range(), + ); + } + } + } + "Crypto" => { + for name in names { + if &name.name == "Cipher" + || &name.name == "Hash" + || &name.name == "IO" + || &name.name == "Protocol" + || &name.name == "PublicKey" + || &name.name == "Random" + || &name.name == "Signature" + || &name.name == "Util" + { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPycryptoImport), + identifier.range(), + ); + } + } + } + "Crypto.Cipher" | "Crypto.Hash" | "Crypto.IO" | "Crypto.Protocol" + | "Crypto.PublicKey" | "Crypto.Random" | "Crypto.Signature" | "Crypto.Util" => { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousPycryptoImport), + identifier.range(), + ); + } "pyghmi" => check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousPyghmiImport), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S405_S405.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S405_S405.py.snap new file mode 100644 index 0000000000000..9f4f8322c927f --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S405_S405.py.snap @@ -0,0 +1,38 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S405.py:1:8: S405 `xml.etree` methods are vulnerable to XML attacks + | +1 | import xml.etree.cElementTree # S405 + | ^^^^^^^^^^^^^^^^^^^^^^ S405 +2 | from xml.etree import cElementTree # S405 +3 | import xml.etree.ElementTree # S405 + | + +S405.py:2:6: S405 `xml.etree` methods are vulnerable to XML attacks + | +1 | import xml.etree.cElementTree # S405 +2 | from xml.etree import cElementTree # S405 + | ^^^^^^^^^ S405 +3 | import xml.etree.ElementTree # S405 +4 | from xml.etree import ElementTree # S405 + | + +S405.py:3:8: S405 `xml.etree` methods are vulnerable to XML attacks + | +1 | import xml.etree.cElementTree # S405 +2 | from xml.etree import cElementTree # S405 +3 | import xml.etree.ElementTree # S405 + | ^^^^^^^^^^^^^^^^^^^^^ S405 +4 | from xml.etree import ElementTree # S405 + | + +S405.py:4:6: S405 `xml.etree` methods are vulnerable to XML attacks + | +2 | from xml.etree import cElementTree # S405 +3 | import xml.etree.ElementTree # S405 +4 | from xml.etree import ElementTree # S405 + | ^^^^^^^^^ S405 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S406_S406.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S406_S406.py.snap new file mode 100644 index 0000000000000..ef1c448cd3579 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S406_S406.py.snap @@ -0,0 +1,28 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S406.py:1:6: S406 `xml.sax` methods are vulnerable to XML attacks + | +1 | from xml import sax # S406 + | ^^^ S406 +2 | import xml.sax as xmls # S406 +3 | import xml.sax # S406 + | + +S406.py:2:8: S406 `xml.sax` methods are vulnerable to XML attacks + | +1 | from xml import sax # S406 +2 | import xml.sax as xmls # S406 + | ^^^^^^^^^^^^^^^ S406 +3 | import xml.sax # S406 + | + +S406.py:3:8: S406 `xml.sax` methods are vulnerable to XML attacks + | +1 | from xml import sax # S406 +2 | import xml.sax as xmls # S406 +3 | import xml.sax # S406 + | ^^^^^^^ S406 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S407_S407.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S407_S407.py.snap new file mode 100644 index 0000000000000..91c88345a4f17 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S407_S407.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S407.py:1:6: S407 `xml.dom.expatbuilder` is vulnerable to XML attacks + | +1 | from xml.dom import expatbuilder # S407 + | ^^^^^^^ S407 +2 | import xml.dom.expatbuilder # S407 + | + +S407.py:2:8: S407 `xml.dom.expatbuilder` is vulnerable to XML attacks + | +1 | from xml.dom import expatbuilder # S407 +2 | import xml.dom.expatbuilder # S407 + | ^^^^^^^^^^^^^^^^^^^^ S407 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S408_S408.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S408_S408.py.snap new file mode 100644 index 0000000000000..e42d754a9ec54 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S408_S408.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S408.py:1:6: S408 `xml.dom.minidom` is vulnerable to XML attacks + | +1 | from xml.dom.minidom import parseString # S408 + | ^^^^^^^^^^^^^^^ S408 +2 | import xml.dom.minidom # S408 + | + +S408.py:2:8: S408 `xml.dom.minidom` is vulnerable to XML attacks + | +1 | from xml.dom.minidom import parseString # S408 +2 | import xml.dom.minidom # S408 + | ^^^^^^^^^^^^^^^ S408 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S409_S409.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S409_S409.py.snap new file mode 100644 index 0000000000000..e65eacfe96f9e --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S409_S409.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S409.py:1:6: S409 `xml.dom.pulldom` is vulnerable to XML attacks + | +1 | from xml.dom.pulldom import parseString # S409 + | ^^^^^^^^^^^^^^^ S409 +2 | import xml.dom.pulldom # S409 + | + +S409.py:2:8: S409 `xml.dom.pulldom` is vulnerable to XML attacks + | +1 | from xml.dom.pulldom import parseString # S409 +2 | import xml.dom.pulldom # S409 + | ^^^^^^^^^^^^^^^ S409 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S412_S412.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S412_S412.py.snap new file mode 100644 index 0000000000000..f6acbda39983f --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S412_S412.py.snap @@ -0,0 +1,10 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S412.py:1:6: S412 `httpoxy` is a set of vulnerabilities that affect application code running inCGI, or CGI-like environments. The use of CGI for web applications should be avoided + | +1 | from twisted.web.twcgi import CGIScript # S412 + | ^^^^^^^^^^^^^^^^^ S412 + | + + diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S413_S413.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S413_S413.py.snap new file mode 100644 index 0000000000000..fa8676bd2d8a1 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S413_S413.py.snap @@ -0,0 +1,38 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +--- +S413.py:1:8: S413 `pycrypto` library is known to have publicly disclosed buffer overflow vulnerability + | +1 | import Crypto.Hash # S413 + | ^^^^^^^^^^^ S413 +2 | from Crypto.Hash import MD2 # S413 +3 | import Crypto.PublicKey # S413 + | + +S413.py:2:6: S413 `pycrypto` library is known to have publicly disclosed buffer overflow vulnerability + | +1 | import Crypto.Hash # S413 +2 | from Crypto.Hash import MD2 # S413 + | ^^^^^^^^^^^ S413 +3 | import Crypto.PublicKey # S413 +4 | from Crypto.PublicKey import RSA # S413 + | + +S413.py:3:8: S413 `pycrypto` library is known to have publicly disclosed buffer overflow vulnerability + | +1 | import Crypto.Hash # S413 +2 | from Crypto.Hash import MD2 # S413 +3 | import Crypto.PublicKey # S413 + | ^^^^^^^^^^^^^^^^ S413 +4 | from Crypto.PublicKey import RSA # S413 + | + +S413.py:4:6: S413 `pycrypto` library is known to have publicly disclosed buffer overflow vulnerability + | +2 | from Crypto.Hash import MD2 # S413 +3 | import Crypto.PublicKey # S413 +4 | from Crypto.PublicKey import RSA # S413 + | ^^^^^^^^^^^^^^^^ S413 + | + + From 8edb48606ba1106b2913378924e9bff26a17c3f9 Mon Sep 17 00:00:00 2001 From: qdegraaf Date: Tue, 2 Jan 2024 19:05:08 +0100 Subject: [PATCH 5/7] Add docs --- .../flake8_bandit/rules/suspicious_imports.rs | 170 +++++++++++++++++- 1 file changed, 167 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs index a8904abf2c5d5..893d02b63c99e 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -9,8 +9,16 @@ use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; use crate::registry::AsRule; -// TODO: Docs -// ref: https://github.com/PyCQA/bandit/blob/6b2e24722bdcc40ea37c3bc155b6856961763814/bandit/blacklists/imports.py#L17 +/// ## What it does +/// Checks for imports of the`telnetlib` module. +/// +/// ## Why is this bad? +/// Telnet is considered insecure. Use SSH or some other encrypted protocol. +/// +/// ## Example +/// ```python +/// import telnetlib +/// ``` #[violation] pub struct SuspiciousTelnetlibImport; @@ -21,6 +29,16 @@ impl Violation for SuspiciousTelnetlibImport { } } +/// ## What it does +/// Checks for imports of the `ftplib` module. +/// +/// ## Why is this bad? +/// FTP is considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol. +/// +/// ## Example +/// ```python +/// import ftplib +/// ``` #[violation] pub struct SuspiciousFtplibImport; @@ -31,6 +49,19 @@ impl Violation for SuspiciousFtplibImport { } } +/// ## What it does +/// Checks for imports of the `pickle`, `cPickle`, `dill` and `shelve` modules. +/// +/// ## Why is this bad? +/// It is possible to construct malicious pickle data which will execute arbitrary code during unpickling. Consider +/// possible security implications associated with these modules. +/// +/// ## Example +/// ```python +/// import pickle +/// ``` +/// /// ## References +/// - [Python Docs](https://docs.python.org/3/library/pickle.html) #[violation] pub struct SuspiciousPickleImport; @@ -41,6 +72,17 @@ impl Violation for SuspiciousPickleImport { } } +/// ## What it does +/// Checks for imports of the `subprocess` module +/// +/// ## Why is this bad? +/// It is possible to inject malicious commands into subprocess calls. Consider possible security implications +/// associated with this module. +/// +/// ## Example +/// ```python +/// import subprocess +/// ``` #[violation] pub struct SuspiciousSubprocessImport; @@ -51,6 +93,18 @@ impl Violation for SuspiciousSubprocessImport { } } +/// ## What it does +/// Checks for imports of the `xml.etree.cElementTree` and `xml.etree.ElementTree` modules +/// +/// ## Why is this bad? +/// Using various methods from these modules to parse untrusted XML data is known to be vulnerable to XML attacks. +/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is +/// called. +/// +/// ## Example +/// ```python +/// import xml.etree.cElementTree +/// ``` #[violation] pub struct SuspiciousXmlEtreeImport; @@ -61,6 +115,18 @@ impl Violation for SuspiciousXmlEtreeImport { } } +/// ## What it does +/// Checks for imports of the `xml.sax` module +/// +/// ## Why is this bad? +/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. +/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is +/// called. +/// +/// ## Example +/// ```python +/// import xml.sax +/// ``` #[violation] pub struct SuspiciousXmlSaxImport; @@ -71,6 +137,18 @@ impl Violation for SuspiciousXmlSaxImport { } } +/// ## What it does +/// Checks for imports of the `xml.dom.expatbuilder` module +/// +/// ## Why is this bad? +/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. +/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is +/// called. +/// +/// ## Example +/// ```python +/// import xml.dom.expatbuilder +/// ``` #[violation] pub struct SuspiciousXmlExpatImport; @@ -81,6 +159,18 @@ impl Violation for SuspiciousXmlExpatImport { } } +/// ## What it does +/// Checks for imports of the `xml.dom.minidom` module +/// +/// ## Why is this bad? +/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. +/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is +/// called. +/// +/// ## Example +/// ```python +/// import xml.dom.minidom +/// ``` #[violation] pub struct SuspiciousXmlMinidomImport; @@ -91,6 +181,18 @@ impl Violation for SuspiciousXmlMinidomImport { } } +/// ## What it does +/// Checks for imports of the `xml.dom.pulldom` module +/// +/// ## Why is this bad? +/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. +/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is +/// called. +/// +/// ## Example +/// ```python +/// import xml.dom.pulldom +/// ``` #[violation] pub struct SuspiciousXmlPulldomImport; @@ -101,6 +203,17 @@ impl Violation for SuspiciousXmlPulldomImport { } } +/// ## What it does +/// Checks for imports of the`lxml` module +/// +/// ## Why is this bad? +/// Using various methods from this module to parse untrusted XML data is known to be vulnerable toXML attacks. Replace +/// vulnerable imports with the equivalent defusedxml package. +/// +/// ## Example +/// ```python +/// import lxml +/// ``` #[violation] pub struct SuspiciousLxmlImport; @@ -111,16 +224,41 @@ impl Violation for SuspiciousLxmlImport { } } +/// ## What it does +/// Checks for imports of the `xmlrpc` module +/// +/// ## Why is this bad? +/// XMLRPC is a particularly dangerous XML module as it is also concerned with communicating data over a network. Use +/// defused.xmlrpc.monkey_patch() function to monkey-patch xmlrpclib and mitigate remote XML attacks. +/// +/// ## Example +/// ```python +/// import xmlrpc +/// ``` #[violation] pub struct SuspiciousXmlrpcImport; impl Violation for SuspiciousXmlrpcImport { #[derive_message_formats] fn message(&self) -> String { - format!("XMLRPC is particularly dangerous as it is also concerned with communicating data over a network") + format!("XMLRPC is vulnerable to remote XML attacks") } } +/// ## What it does +/// Checks for imports of `wsgiref.handlers.CGIHandler` and `twisted.web.twcgi.CGIScript` +/// +/// ## Why is this bad? +/// httpoxy is a set of vulnerabilities that affect application code running in CGI, or CGI-like environments. The use +/// of CGI for web applications should be avoided to prevent this class of attack. More details are available. +/// +/// ## Example +/// ```python +/// import wsgiref.handlers.CGIHandler +/// ``` +/// +/// ## References +/// - [httpoxy website](https://httpoxy.org/) #[violation] pub struct SuspiciousHttpoxyImport; @@ -131,6 +269,20 @@ impl Violation for SuspiciousHttpoxyImport { } } +/// ## What it does +/// Checks for imports of several unsafe Crypto modules. +/// +/// ## Why is this bad? +/// pycrypto library is known to have publicly disclosed buffer overflow vulnerability. It is no longer actively +/// maintained and has been deprecated in favor of pyca/cryptography library. +/// +/// ## Example +/// ```python +/// import Crypto.Random +/// ``` +/// +/// ## References +/// - [Buffer Overflow Issue](https://github.com/pycrypto/pycrypto/issues/176) #[violation] pub struct SuspiciousPycryptoImport; @@ -143,6 +295,18 @@ impl Violation for SuspiciousPycryptoImport { } } +/// ## What it does +/// Checks for imports of the `pyghmi` module +/// +/// ## Why is this bad? +/// `pyghmi` is an IPMI related module. IPMI is considered insecure. Use an encrypted protocol. +/// ## Example +/// ```python +/// import pyghmi +/// ``` +/// +/// ## References +/// - [Buffer Overflow Issue](https://github.com/pycrypto/pycrypto/issues/176) #[violation] pub struct SuspiciousPyghmiImport; From 78988daeb4aa9d81ae53d1a6397f3b45b662ad3c Mon Sep 17 00:00:00 2001 From: qdegraaf Date: Tue, 2 Jan 2024 19:10:23 +0100 Subject: [PATCH 6/7] Regen snapshots --- ...uff_linter__rules__flake8_bandit__tests__S411_S411.py.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap index 09948c33ab82d..0cb05d60b5de0 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S411_S411.py.snap @@ -1,14 +1,14 @@ --- source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs --- -S411.py:1:8: S411 XMLRPC is particularly dangerous as it is also concerned with communicating data over a network +S411.py:1:8: S411 XMLRPC is vulnerable to remote XML attacks | 1 | import xmlrpc # S411 | ^^^^^^ S411 2 | from xmlrpc import server # S411 | -S411.py:2:6: S411 XMLRPC is particularly dangerous as it is also concerned with communicating data over a network +S411.py:2:6: S411 XMLRPC is vulnerable to remote XML attacks | 1 | import xmlrpc # S411 2 | from xmlrpc import server # S411 From c9aafeb9f1f798d405f4c8858d873dd1a6d18112 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 3 Jan 2024 13:18:37 -0500 Subject: [PATCH 7/7] Move to preview --- crates/ruff_linter/src/codes.rs | 28 ++-- .../flake8_bandit/rules/suspicious_imports.rs | 134 ++++++++++-------- ...s__flake8_bandit__tests__S401_S401.py.snap | 4 +- ...s__flake8_bandit__tests__S402_S402.py.snap | 4 +- ...s__flake8_bandit__tests__S403_S403.py.snap | 16 +-- ...s__flake8_bandit__tests__S415_S415.py.snap | 4 +- 6 files changed, 104 insertions(+), 86 deletions(-) diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index a1689cf9a23f5..905e249e2af10 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -627,20 +627,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Bandit, "321") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousFTPLibUsage), (Flake8Bandit, "323") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousUnverifiedContextUsage), (Flake8Bandit, "324") => (RuleGroup::Stable, rules::flake8_bandit::rules::HashlibInsecureHashFunction), - (Flake8Bandit, "401") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousTelnetlibImport), - (Flake8Bandit, "402") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousFtplibImport), - (Flake8Bandit, "403") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPickleImport), - (Flake8Bandit, "404") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousSubprocessImport), - (Flake8Bandit, "405") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlEtreeImport), - (Flake8Bandit, "406") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlSaxImport), - (Flake8Bandit, "407") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlExpatImport), - (Flake8Bandit, "408") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlMinidomImport), - (Flake8Bandit, "409") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlPulldomImport), - (Flake8Bandit, "410") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousLxmlImport), - (Flake8Bandit, "411") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXmlrpcImport), - (Flake8Bandit, "412") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousHttpoxyImport), - (Flake8Bandit, "413") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPycryptoImport), - (Flake8Bandit, "415") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousPyghmiImport), + (Flake8Bandit, "401") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousTelnetlibImport), + (Flake8Bandit, "402") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousFtplibImport), + (Flake8Bandit, "403") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousPickleImport), + (Flake8Bandit, "404") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousSubprocessImport), + (Flake8Bandit, "405") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousXmlEtreeImport), + (Flake8Bandit, "406") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousXmlSaxImport), + (Flake8Bandit, "407") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousXmlExpatImport), + (Flake8Bandit, "408") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousXmlMinidomImport), + (Flake8Bandit, "409") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousXmlPulldomImport), + (Flake8Bandit, "410") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousLxmlImport), + (Flake8Bandit, "411") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousXmlrpcImport), + (Flake8Bandit, "412") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousHttpoxyImport), + (Flake8Bandit, "413") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousPycryptoImport), + (Flake8Bandit, "415") => (RuleGroup::Preview, rules::flake8_bandit::rules::SuspiciousPyghmiImport), (Flake8Bandit, "501") => (RuleGroup::Stable, rules::flake8_bandit::rules::RequestWithNoCertValidation), (Flake8Bandit, "505") => (RuleGroup::Preview, rules::flake8_bandit::rules::WeakCryptographicKey), (Flake8Bandit, "506") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnsafeYAMLLoad), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs index 893d02b63c99e..e8d8bbed5a7ef 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -13,7 +13,8 @@ use crate::registry::AsRule; /// Checks for imports of the`telnetlib` module. /// /// ## Why is this bad? -/// Telnet is considered insecure. Use SSH or some other encrypted protocol. +/// Telnet is considered insecure. Instead, ise SSH or another encrypted +/// protocol. /// /// ## Example /// ```python @@ -25,7 +26,7 @@ pub struct SuspiciousTelnetlibImport; impl Violation for SuspiciousTelnetlibImport { #[derive_message_formats] fn message(&self) -> String { - format!("`telnetlib` and related modules are considered insecure. Use SSH or some other encrypted protocol") + format!("`telnetlib` and related modules are considered insecure. Use SSH or another encrypted protocol.") } } @@ -33,7 +34,8 @@ impl Violation for SuspiciousTelnetlibImport { /// Checks for imports of the `ftplib` module. /// /// ## Why is this bad? -/// FTP is considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol. +/// FTP is considered insecure. Instead, use SSH, SFTP, SCP, or another +/// encrypted protocol. /// /// ## Example /// ```python @@ -45,16 +47,17 @@ pub struct SuspiciousFtplibImport; impl Violation for SuspiciousFtplibImport { #[derive_message_formats] fn message(&self) -> String { - format!("`ftplib` and related modules are considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol") + format!("`ftplib` and related modules are considered insecure. Use SSH, SFTP, SCP, or another encrypted protocol.") } } /// ## What it does -/// Checks for imports of the `pickle`, `cPickle`, `dill` and `shelve` modules. +/// Checks for imports of the `pickle`, `cPickle`, `dill`, and `shelve` modules. /// /// ## Why is this bad? -/// It is possible to construct malicious pickle data which will execute arbitrary code during unpickling. Consider -/// possible security implications associated with these modules. +/// It is possible to construct malicious pickle data which will execute +/// arbitrary code during unpickling. Consider possible security implications +/// associated with these modules. /// /// ## Example /// ```python @@ -68,16 +71,16 @@ pub struct SuspiciousPickleImport; impl Violation for SuspiciousPickleImport { #[derive_message_formats] fn message(&self) -> String { - format!("`pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure") + format!("`pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure") } } /// ## What it does -/// Checks for imports of the `subprocess` module +/// Checks for imports of the `subprocess` module. /// /// ## Why is this bad? -/// It is possible to inject malicious commands into subprocess calls. Consider possible security implications -/// associated with this module. +/// It is possible to inject malicious commands into subprocess calls. Consider +/// possible security implications associated with this module. /// /// ## Example /// ```python @@ -97,9 +100,10 @@ impl Violation for SuspiciousSubprocessImport { /// Checks for imports of the `xml.etree.cElementTree` and `xml.etree.ElementTree` modules /// /// ## Why is this bad? -/// Using various methods from these modules to parse untrusted XML data is known to be vulnerable to XML attacks. -/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is -/// called. +/// Using various methods from these modules to parse untrusted XML data is +/// known to be vulnerable to XML attacks. Replace vulnerable imports with the +/// equivalent `defusedxml` package, or make sure `defusedxml.defuse_stdlib()` is +/// called before parsing XML data. /// /// ## Example /// ```python @@ -116,12 +120,13 @@ impl Violation for SuspiciousXmlEtreeImport { } /// ## What it does -/// Checks for imports of the `xml.sax` module +/// Checks for imports of the `xml.sax` module. /// /// ## Why is this bad? -/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. -/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is -/// called. +/// Using various methods from these modules to parse untrusted XML data is +/// known to be vulnerable to XML attacks. Replace vulnerable imports with the +/// equivalent `defusedxml` package, or make sure `defusedxml.defuse_stdlib()` is +/// called before parsing XML data. /// /// ## Example /// ```python @@ -138,12 +143,13 @@ impl Violation for SuspiciousXmlSaxImport { } /// ## What it does -/// Checks for imports of the `xml.dom.expatbuilder` module +/// Checks for imports of the `xml.dom.expatbuilder` module. /// /// ## Why is this bad? -/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. -/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is -/// called. +/// Using various methods from these modules to parse untrusted XML data is +/// known to be vulnerable to XML attacks. Replace vulnerable imports with the +/// equivalent `defusedxml` package, or make sure `defusedxml.defuse_stdlib()` is +/// called before parsing XML data. /// /// ## Example /// ```python @@ -160,12 +166,13 @@ impl Violation for SuspiciousXmlExpatImport { } /// ## What it does -/// Checks for imports of the `xml.dom.minidom` module +/// Checks for imports of the `xml.dom.minidom` module. /// /// ## Why is this bad? -/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. -/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is -/// called. +/// Using various methods from these modules to parse untrusted XML data is +/// known to be vulnerable to XML attacks. Replace vulnerable imports with the +/// equivalent `defusedxml` package, or make sure `defusedxml.defuse_stdlib()` is +/// called before parsing XML data. /// /// ## Example /// ```python @@ -182,12 +189,13 @@ impl Violation for SuspiciousXmlMinidomImport { } /// ## What it does -/// Checks for imports of the `xml.dom.pulldom` module +/// Checks for imports of the `xml.dom.pulldom` module. /// /// ## Why is this bad? -/// Using various methods from this modules to parse untrusted XML data is known to be vulnerable to XML attacks. -/// Replace vulnerable imports with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is -/// called. +/// Using various methods from these modules to parse untrusted XML data is +/// known to be vulnerable to XML attacks. Replace vulnerable imports with the +/// equivalent `defusedxml` package, or make sure `defusedxml.defuse_stdlib()` is +/// called before parsing XML data. /// /// ## Example /// ```python @@ -204,11 +212,12 @@ impl Violation for SuspiciousXmlPulldomImport { } /// ## What it does -/// Checks for imports of the`lxml` module +/// Checks for imports of the`lxml` module. /// /// ## Why is this bad? -/// Using various methods from this module to parse untrusted XML data is known to be vulnerable toXML attacks. Replace -/// vulnerable imports with the equivalent defusedxml package. +/// Using various methods from the `lxml` module to parse untrusted XML data is +/// known to be vulnerable to XML attacks. Replace vulnerable imports with the +/// equivalent `defusedxml` package. /// /// ## Example /// ```python @@ -225,11 +234,13 @@ impl Violation for SuspiciousLxmlImport { } /// ## What it does -/// Checks for imports of the `xmlrpc` module +/// Checks for imports of the `xmlrpc` module. /// /// ## Why is this bad? -/// XMLRPC is a particularly dangerous XML module as it is also concerned with communicating data over a network. Use -/// defused.xmlrpc.monkey_patch() function to monkey-patch xmlrpclib and mitigate remote XML attacks. +/// XMLRPC is a particularly dangerous XML module as it is also concerned with +/// communicating data over a network. Use the `defused.xmlrpc.monkey_patch()` +/// function to monkey-patch the `xmlrpclib` module and mitigate remote XML +/// attacks. /// /// ## Example /// ```python @@ -246,11 +257,13 @@ impl Violation for SuspiciousXmlrpcImport { } /// ## What it does -/// Checks for imports of `wsgiref.handlers.CGIHandler` and `twisted.web.twcgi.CGIScript` +/// Checks for imports of `wsgiref.handlers.CGIHandler` and +/// `twisted.web.twcgi.CGIScript`. /// /// ## Why is this bad? -/// httpoxy is a set of vulnerabilities that affect application code running in CGI, or CGI-like environments. The use -/// of CGI for web applications should be avoided to prevent this class of attack. More details are available. +/// httpoxy is a set of vulnerabilities that affect application code running in +/// CGI or CGI-like environments. The use of CGI for web applications should be +/// avoided to prevent this class of attack. /// /// ## Example /// ```python @@ -270,11 +283,12 @@ impl Violation for SuspiciousHttpoxyImport { } /// ## What it does -/// Checks for imports of several unsafe Crypto modules. +/// Checks for imports of several unsafe cryptography modules. /// /// ## Why is this bad? -/// pycrypto library is known to have publicly disclosed buffer overflow vulnerability. It is no longer actively -/// maintained and has been deprecated in favor of pyca/cryptography library. +/// The `pycrypto` library is known to have a publicly disclosed buffer +/// overflow vulnerability. It is no longer actively maintained and has been +/// deprecated in favor of the `pyca/cryptography` library. /// /// ## Example /// ```python @@ -296,10 +310,12 @@ impl Violation for SuspiciousPycryptoImport { } /// ## What it does -/// Checks for imports of the `pyghmi` module +/// Checks for imports of the `pyghmi` module. /// /// ## Why is this bad? -/// `pyghmi` is an IPMI related module. IPMI is considered insecure. Use an encrypted protocol. +/// `pyghmi` is an IPMI-related module, but IPMI is considered insecure. +/// Instead, use an encrypted protocol. +/// /// ## Example /// ```python /// import pyghmi @@ -313,7 +329,7 @@ pub struct SuspiciousPyghmiImport; impl Violation for SuspiciousPyghmiImport { #[derive_message_formats] fn message(&self) -> String { - format!("An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol") + format!("An IPMI-related module is being imported. Prefer an encrypted protocol over IPMI.") } } @@ -422,7 +438,7 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { ), "xml.etree" => { for name in names { - if &name.name == "cElementTree" || &name.name == "ElementTree" { + if matches!(name.name.as_str(), "cElementTree" | "ElementTree") { check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousXmlEtreeImport), @@ -440,7 +456,7 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { } "xml" => { for name in names { - if &name.name == "sax" { + if name.name.as_str() == "sax" { check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousXmlSaxImport), @@ -503,7 +519,7 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { ), "wsgiref.handlers" => { for name in names { - if &name.name == "CGIHandler" { + if name.name.as_str() == "CGIHandler" { check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousHttpoxyImport), @@ -514,7 +530,7 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { } "twisted.web.twcgi" => { for name in names { - if &name.name == "CGIScript" { + if name.name.as_str() == "CGIScript" { check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousHttpoxyImport), @@ -525,15 +541,17 @@ pub(crate) fn suspicious_imports(checker: &mut Checker, stmt: &Stmt) { } "Crypto" => { for name in names { - if &name.name == "Cipher" - || &name.name == "Hash" - || &name.name == "IO" - || &name.name == "Protocol" - || &name.name == "PublicKey" - || &name.name == "Random" - || &name.name == "Signature" - || &name.name == "Util" - { + if matches!( + name.name.as_str(), + "Cipher" + | "Hash" + | "IO" + | "Protocol" + | "PublicKey" + | "Random" + | "Signature" + | "Util" + ) { check_and_push_diagnostic( checker, DiagnosticKind::from(SuspiciousPycryptoImport), diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap index e886364f594b2..238e12cb37a0b 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S401_S401.py.snap @@ -1,14 +1,14 @@ --- source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs --- -S401.py:1:8: S401 `telnetlib` and related modules are considered insecure. Use SSH or some other encrypted protocol +S401.py:1:8: S401 `telnetlib` and related modules are considered insecure. Use SSH or another encrypted protocol. | 1 | import telnetlib # S401 | ^^^^^^^^^ S401 2 | from telnetlib import Telnet # S401 | -S401.py:2:6: S401 `telnetlib` and related modules are considered insecure. Use SSH or some other encrypted protocol +S401.py:2:6: S401 `telnetlib` and related modules are considered insecure. Use SSH or another encrypted protocol. | 1 | import telnetlib # S401 2 | from telnetlib import Telnet # S401 diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap index a61b13c07a886..76133c6a5e3f7 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S402_S402.py.snap @@ -1,14 +1,14 @@ --- source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs --- -S402.py:1:8: S402 `ftplib` and related modules are considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol +S402.py:1:8: S402 `ftplib` and related modules are considered insecure. Use SSH, SFTP, SCP, or another encrypted protocol. | 1 | import ftplib # S402 | ^^^^^^ S402 2 | from ftplib import FTP # S402 | -S402.py:2:6: S402 `ftplib` and related modules are considered insecure. Use SSH/SFTP/SCP or some other encrypted protocol +S402.py:2:6: S402 `ftplib` and related modules are considered insecure. Use SSH, SFTP, SCP, or another encrypted protocol. | 1 | import ftplib # S402 2 | from ftplib import FTP # S402 diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap index 2933b0436e96f..40a790297e356 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S403_S403.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs --- -S403.py:1:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:1:8: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 1 | import dill # S403 | ^^^^ S403 @@ -9,7 +9,7 @@ S403.py:1:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 3 | import shelve | -S403.py:2:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:2:6: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 1 | import dill # S403 2 | from dill import objects # S403 @@ -18,7 +18,7 @@ S403.py:2:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 4 | from shelve import open | -S403.py:3:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:3:8: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 1 | import dill # S403 2 | from dill import objects # S403 @@ -28,7 +28,7 @@ S403.py:3:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 5 | import cPickle | -S403.py:4:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:4:6: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 2 | from dill import objects # S403 3 | import shelve @@ -38,7 +38,7 @@ S403.py:4:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 6 | from cPickle import load | -S403.py:5:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:5:8: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 3 | import shelve 4 | from shelve import open @@ -48,7 +48,7 @@ S403.py:5:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 7 | import pickle | -S403.py:6:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:6:6: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 4 | from shelve import open 5 | import cPickle @@ -58,7 +58,7 @@ S403.py:6:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 8 | from pickle import load | -S403.py:7:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:7:8: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 5 | import cPickle 6 | from cPickle import load @@ -67,7 +67,7 @@ S403.py:7:8: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly 8 | from pickle import load | -S403.py:8:6: S403 `pickle`, `cPickle`, `dill` and `shelve` modules are possibly insecure +S403.py:8:6: S403 `pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure | 6 | from cPickle import load 7 | import pickle diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap index af87b7c06dbfa..3c47930c4b044 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S415_S415.py.snap @@ -1,14 +1,14 @@ --- source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs --- -S415.py:1:8: S415 An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol +S415.py:1:8: S415 An IPMI-related module is being imported. Prefer an encrypted protocol over IPMI. | 1 | import pyghmi # S415 | ^^^^^^ S415 2 | from pyghmi import foo # S415 | -S415.py:2:6: S415 An IPMI-related module is being imported. IPMI is considered insecure. Use an encrypted protocol +S415.py:2:6: S415 An IPMI-related module is being imported. Prefer an encrypted protocol over IPMI. | 1 | import pyghmi # S415 2 | from pyghmi import foo # S415