Repository: PyCQA/bandit
Pull request #1149 (2024-06-23 04:12:48)

Add test for usage of FTP_TLS
This change adds an FTP_TLS call to the examples. A high severity
error is no longer reported as a result of the fix in PR #1148
that explicitly now matches blacklist call qualified names rather
than using a file glob.
    
However, you will notice that there is one more high severity
issue reported in the tests as a result of the import of
ftplib.FTP_TLS because the blacklist import is only checking for
"ftplib".
    
Fixes: #148
    
Signed-off-by: Eric Brown <eric_wade_brown@yahoo.com>


Patch:
diff --git a/bandit/blacklists/calls.py b/bandit/blacklists/calls.py
index d69f5dd..3d5f21c 100644
--- a/bandit/blacklists/calls.py
+++ b/bandit/blacklists/calls.py
@@ -537,7 +537,7 @@ def gen_blacklist():
             "telnetlib",
             "B312",
             issue.Cwe.CLEARTEXT_TRANSMISSION,
-            ["telnetlib.*"],
+            ["telnetlib.Telnet"],
             "Telnet-related functions are being called. Telnet is considered "
             "insecure. Use SSH or some other encrypted protocol.",
             "HIGH",
@@ -662,7 +662,7 @@ def gen_blacklist():
             "ftplib",
             "B321",
             issue.Cwe.CLEARTEXT_TRANSMISSION,
-            ["ftplib.*"],
+            ["ftplib.FTP"],
             "FTP-related functions are being called. FTP is considered "
             "insecure. Use SSH/SFTP/SCP or some other encrypted protocol.",
             "HIGH",
diff --git a/bandit/core/blacklisting.py b/bandit/core/blacklisting.py
index 2f84ae0..2bbb093 100644
--- a/bandit/core/blacklisting.py
+++ b/bandit/core/blacklisting.py
@@ -3,7 +3,6 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 import ast
-import fnmatch
 
 from bandit.core import issue
 
@@ -55,7 +54,7 @@ def blacklist(context, config):
                     name = context.call_keywords["name"]
         for check in blacklists[node_type]:
             for qn in check["qualnames"]:
-                if name is not None and fnmatch.fnmatch(name, qn):
+                if name is not None and name == qn:
                     return report_issue(check, name)
 
     if node_type.startswith("Import"):
diff --git a/bandit/core/context.py b/bandit/core/context.py
index 76b5092..8a2d4fb 100644
--- a/bandit/core/context.py
+++ b/bandit/core/context.py
@@ -193,7 +193,7 @@ class Context:
         elif isinstance(literal, ast.Tuple):
             return_tuple = tuple()
             for ti in literal.elts:
-                return_tuple = return_tuple + (self._get_literal_value(ti),)
+                return_tuple += (self._get_literal_value(ti),)
             literal_value = return_tuple
 
         elif isinstance(literal, ast.Set):
diff --git a/bandit/formatters/xml.py b/bandit/formatters/xml.py
index 6e196d9..d2b2067 100644
--- a/bandit/formatters/xml.py
+++ b/bandit/formatters/xml.py
@@ -65,7 +65,7 @@ def report(manager, fileobj, sev_level, conf_level, lines=-1):
             "Test ID: %s Severity: %s Confidence: %s\nCWE: %s\n%s\n"
             "Location %s:%s"
         )
-        text = text % (
+        text %= (
             issue.test_id,
             issue.severity,
             issue.confidence,
diff --git a/bandit/plugins/injection_wildcard.py b/bandit/plugins/injection_wildcard.py
index 94d03b3..46f6b5b 100644
--- a/bandit/plugins/injection_wildcard.py
+++ b/bandit/plugins/injection_wildcard.py
@@ -124,7 +124,7 @@ def linux_commands_wildcard_injection(context, config):
             argument_string = ""
             if isinstance(call_argument, list):
                 for li in call_argument:
-                    argument_string = argument_string + f" {li}"
+                    argument_string += f" {li}"
             elif isinstance(call_argument, str):
                 argument_string = call_argument
 
diff --git a/examples/ftplib.py b/examples/ftplib.py
index beaeb74..6664ed0 100644
--- a/examples/ftplib.py
+++ b/examples/ftplib.py
@@ -1,9 +1,24 @@
 from ftplib import FTP
+from ftplib import FTP_TLS
 
+
+# bad
 ftp = FTP('ftp.debian.org')
 ftp.login()
 
 ftp.cwd('debian')
 ftp.retrlines('LIST')
 
-ftp.quit()
\ No newline at end of file
+ftp.quit()
+
+# okay
+ftp = ftplib.FTP_TLS(
+    "ftp.us.debian.org",
+    context=ssl.create_default_context(),
+)
+ftp.login()
+
+ftp.cwd("debian")
+ftp.retrlines("LIST")
+
+ftp.quit()


Test patch:
diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py
index fd96796..a92fe3f 100644
--- a/tests/functional/test_functional.py
+++ b/tests/functional/test_functional.py
@@ -246,8 +246,8 @@ class FunctionalTests(testtools.TestCase):
     def test_ftp_usage(self):
         """Test for `import ftplib` and FTP.* calls."""
         expect = {
-            "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2},
-            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2},
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3},
         }
         self.check_example("ftplib.py", expect)