From 5c93a524f1c178c230b0830aa1413be702027e9d Mon Sep 17 00:00:00 2001 From: qdegraaf <34540841+qdegraaf@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:26:26 +0100 Subject: [PATCH] [`flake8-bandit`] Implement `S4XX` suspicious import rules (#8831) ## Summary Adds all `S4XX` rules to the [flake8-bandit](https://github.com/tylerwince/flake8-bandit) plugin port. There is a lot of documentation to write, some tests can be expanded and implementation can probably be refactored to be more compact. As there is some discussion on whether this is actually useful. (See: https://github.com/astral-sh/ruff/issues/1646#issuecomment-1732331441), wanted to check which rules we want to have before I go through the process of polishing this up. ## Test Plan Fixtures for all rules based on `flake8-bandit` [tests](https://github.com/tylerwince/flake8-bandit/tree/main/tests) ## Issue link Refers: https://github.com/astral-sh/ruff/issues/1646 --- .../test/fixtures/flake8_bandit/S401.py | 2 + .../test/fixtures/flake8_bandit/S402.py | 2 + .../test/fixtures/flake8_bandit/S403.py | 8 + .../test/fixtures/flake8_bandit/S404.py | 3 + .../test/fixtures/flake8_bandit/S405.py | 4 + .../test/fixtures/flake8_bandit/S406.py | 3 + .../test/fixtures/flake8_bandit/S407.py | 2 + .../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 | 1 + .../test/fixtures/flake8_bandit/S413.py | 4 + .../test/fixtures/flake8_bandit/S415.py | 3 + .../src/checkers/ast/analyze/statement.rs | 36 ++ crates/ruff_linter/src/codes.rs | 14 + .../src/rules/flake8_bandit/mod.rs | 14 + .../src/rules/flake8_bandit/rules/mod.rs | 2 + .../flake8_bandit/rules/suspicious_imports.rs | 592 ++++++++++++++++++ ...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__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__S410_S410.py.snap | 18 + ...s__flake8_bandit__tests__S411_S411.py.snap | 18 + ...s__flake8_bandit__tests__S412_S412.py.snap | 10 + ...s__flake8_bandit__tests__S413_S413.py.snap | 38 ++ ...s__flake8_bandit__tests__S415_S415.py.snap | 18 + ruff.schema.json | 17 + 34 files changed, 1079 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/resources/test/fixtures/flake8_bandit/S415.py create mode 100644 crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs 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__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__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__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 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/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..2aec54eb8c936 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py @@ -0,0 +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/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..8bf2d4a63b184 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py @@ -0,0 +1,4 @@ +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/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..e7d3841382f4c --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py @@ -0,0 +1,2 @@ +from xml.dom import expatbuilder # S407 +import xml.dom.expatbuilder # 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..5ff308d53d35a --- /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..1b8163323ab93 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000000000..b0ec780ca8033 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py @@ -0,0 +1,4 @@ +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/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 20ed78c8350f5..4c5360beb250e 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -552,6 +552,24 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::DeprecatedMockImport) { pyupgrade::rules::deprecated_mock_import(checker, stmt); } + if checker.any_enabled(&[ + Rule::SuspiciousTelnetlibImport, + Rule::SuspiciousFtplibImport, + Rule::SuspiciousPickleImport, + Rule::SuspiciousSubprocessImport, + Rule::SuspiciousXmlEtreeImport, + Rule::SuspiciousXmlSaxImport, + Rule::SuspiciousXmlExpatImport, + Rule::SuspiciousXmlMinidomImport, + Rule::SuspiciousXmlPulldomImport, + Rule::SuspiciousLxmlImport, + Rule::SuspiciousXmlrpcImport, + Rule::SuspiciousHttpoxyImport, + Rule::SuspiciousPycryptoImport, + Rule::SuspiciousPyghmiImport, + ]) { + flake8_bandit::rules::suspicious_imports(checker, stmt); + } for alias in names { if checker.enabled(Rule::NonAsciiImportName) { @@ -751,6 +769,24 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pyupgrade::rules::unnecessary_builtin_import(checker, stmt, module, names); } } + if checker.any_enabled(&[ + Rule::SuspiciousTelnetlibImport, + Rule::SuspiciousFtplibImport, + Rule::SuspiciousPickleImport, + Rule::SuspiciousSubprocessImport, + Rule::SuspiciousXmlEtreeImport, + Rule::SuspiciousXmlSaxImport, + Rule::SuspiciousXmlExpatImport, + Rule::SuspiciousXmlMinidomImport, + Rule::SuspiciousXmlPulldomImport, + Rule::SuspiciousLxmlImport, + Rule::SuspiciousXmlrpcImport, + Rule::SuspiciousHttpoxyImport, + Rule::SuspiciousPycryptoImport, + Rule::SuspiciousPyghmiImport, + ]) { + 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 f964f7da53fd6..905e249e2af10 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -627,6 +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::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/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index ce041669f1782..a27f8b19444d8 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -45,6 +45,20 @@ 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::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::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"))] #[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 ee1de347d6152..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,6 +51,7 @@ 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; 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..e8d8bbed5a7ef --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_imports.rs @@ -0,0 +1,592 @@ +//! 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, Stmt}; +use ruff_text_size::{Ranged, TextRange}; + +use crate::checkers::ast::Checker; +use crate::registry::AsRule; + +/// ## What it does +/// Checks for imports of the`telnetlib` module. +/// +/// ## Why is this bad? +/// Telnet is considered insecure. Instead, ise SSH or another encrypted +/// protocol. +/// +/// ## Example +/// ```python +/// import telnetlib +/// ``` +#[violation] +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 another encrypted protocol.") + } +} + +/// ## What it does +/// Checks for imports of the `ftplib` module. +/// +/// ## Why is this bad? +/// FTP is considered insecure. Instead, use SSH, SFTP, SCP, or another +/// encrypted protocol. +/// +/// ## Example +/// ```python +/// import ftplib +/// ``` +#[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 another encrypted protocol.") + } +} + +/// ## 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; + +impl Violation for SuspiciousPickleImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`pickle`, `cPickle`, `dill`, and `shelve` modules are possibly insecure") + } +} + +/// ## 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; + +impl Violation for SuspiciousSubprocessImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`subprocess` module is possibly insecure") + } +} + +/// ## 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 before parsing XML data. +/// +/// ## Example +/// ```python +/// import xml.etree.cElementTree +/// ``` +#[violation] +pub struct SuspiciousXmlEtreeImport; + +impl Violation for SuspiciousXmlEtreeImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.etree` methods are vulnerable to XML attacks") + } +} + +/// ## What it does +/// Checks for imports of the `xml.sax` module. +/// +/// ## 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 before parsing XML data. +/// +/// ## Example +/// ```python +/// import xml.sax +/// ``` +#[violation] +pub struct SuspiciousXmlSaxImport; + +impl Violation for SuspiciousXmlSaxImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.sax` methods are vulnerable to XML attacks") + } +} + +/// ## What it does +/// Checks for imports of the `xml.dom.expatbuilder` module. +/// +/// ## 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 before parsing XML data. +/// +/// ## Example +/// ```python +/// import xml.dom.expatbuilder +/// ``` +#[violation] +pub struct SuspiciousXmlExpatImport; + +impl Violation for SuspiciousXmlExpatImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.dom.expatbuilder` is vulnerable to XML attacks") + } +} + +/// ## What it does +/// Checks for imports of the `xml.dom.minidom` module. +/// +/// ## 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 before parsing XML data. +/// +/// ## Example +/// ```python +/// import xml.dom.minidom +/// ``` +#[violation] +pub struct SuspiciousXmlMinidomImport; + +impl Violation for SuspiciousXmlMinidomImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.dom.minidom` is vulnerable to XML attacks") + } +} + +/// ## What it does +/// Checks for imports of the `xml.dom.pulldom` module. +/// +/// ## 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 before parsing XML data. +/// +/// ## Example +/// ```python +/// import xml.dom.pulldom +/// ``` +#[violation] +pub struct SuspiciousXmlPulldomImport; + +impl Violation for SuspiciousXmlPulldomImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`xml.dom.pulldom` is vulnerable to XML attacks") + } +} + +/// ## What it does +/// Checks for imports of the`lxml` module. +/// +/// ## Why is this bad? +/// 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 +/// import lxml +/// ``` +#[violation] +pub struct SuspiciousLxmlImport; + +impl Violation for SuspiciousLxmlImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("`lxml` is vulnerable to XML attacks") + } +} + +/// ## 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 the `defused.xmlrpc.monkey_patch()` +/// function to monkey-patch the `xmlrpclib` module 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 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. +/// +/// ## Example +/// ```python +/// import wsgiref.handlers.CGIHandler +/// ``` +/// +/// ## References +/// - [httpoxy website](https://httpoxy.org/) +#[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") + } +} + +/// ## What it does +/// Checks for imports of several unsafe cryptography modules. +/// +/// ## Why is this bad? +/// 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 +/// import Crypto.Random +/// ``` +/// +/// ## References +/// - [Buffer Overflow Issue](https://github.com/pycrypto/pycrypto/issues/176) +#[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" + ) + } +} + +/// ## What it does +/// Checks for imports of the `pyghmi` module. +/// +/// ## Why is this bad? +/// `pyghmi` is an IPMI-related module, but IPMI is considered insecure. +/// Instead, use an encrypted protocol. +/// +/// ## Example +/// ```python +/// import pyghmi +/// ``` +/// +/// ## References +/// - [Buffer Overflow Issue](https://github.com/pycrypto/pycrypto/issues/176) +#[violation] +pub struct SuspiciousPyghmiImport; + +impl Violation for SuspiciousPyghmiImport { + #[derive_message_formats] + fn message(&self) -> String { + format!("An IPMI-related module is being imported. Prefer an encrypted protocol over IPMI.") + } +} + +/// 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, .. }) => { + for name in names { + match name.name.as_str() { + "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, + ), + "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), + name.range, + ), + "xmlrpc" => check_and_push_diagnostic( + checker, + 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), + name.range, + ), + _ => {} + } + } + } + Stmt::ImportFrom(ast::StmtImportFrom { module, names, .. }) => { + let Some(identifier) = module else { return }; + match identifier.as_str() { + "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(), + ), + "xml.etree" => { + for name in names { + if matches!(name.name.as_str(), "cElementTree" | "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.as_str() == "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), + identifier.range(), + ), + "xmlrpc" => check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousXmlrpcImport), + identifier.range(), + ), + "wsgiref.handlers" => { + for name in names { + if name.name.as_str() == "CGIHandler" { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousHttpoxyImport), + identifier.range(), + ); + } + } + } + "twisted.web.twcgi" => { + for name in names { + if name.name.as_str() == "CGIScript" { + check_and_push_diagnostic( + checker, + DiagnosticKind::from(SuspiciousHttpoxyImport), + identifier.range(), + ); + } + } + } + "Crypto" => { + for name in names { + if matches!( + name.name.as_str(), + "Cipher" + | "Hash" + | "IO" + | "Protocol" + | "PublicKey" + | "Random" + | "Signature" + | "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), + identifier.range(), + ), + _ => {} + } + } + _ => panic!("Expected Stmt::Import | Stmt::ImportFrom"), + }; +} + +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..238e12cb37a0b --- /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 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 another 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..76133c6a5e3f7 --- /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 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 another 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..40a790297e356 --- /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__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__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..0cb05d60b5de0 --- /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 vulnerable to remote XML attacks + | +1 | import xmlrpc # S411 + | ^^^^^^ S411 +2 | from xmlrpc import server # S411 + | + +S411.py:2:6: S411 XMLRPC is vulnerable to remote XML attacks + | +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__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 + | + + 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..3c47930c4b044 --- /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. 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. Prefer an encrypted protocol over IPMI. + | +1 | import pyghmi # S415 +2 | from pyghmi import foo # S415 + | ^^^^^^ S415 + | + + diff --git a/ruff.schema.json b/ruff.schema.json index dce12c257b2b2..40d0ecb8ee5dc 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3492,6 +3492,23 @@ "S321", "S323", "S324", + "S4", + "S40", + "S401", + "S402", + "S403", + "S404", + "S405", + "S406", + "S407", + "S408", + "S409", + "S41", + "S410", + "S411", + "S412", + "S413", + "S415", "S5", "S50", "S501",