From 8c193a463ba6cf453748662021c3de9f05db2f8d Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Thu, 30 Jun 2022 20:09:13 -0700 Subject: [PATCH] More precise testing of plugins Instead of relying on a count of the severity and confidence levels found within an example file, make use of Python's native unit testing to verify the results of a plugin. The existing method of confirming counts can be inaccurate. It's very easy to have a false positive simply because one issue extra was found and one issue was missed, thus giving the same count. It tells nothing of the validation of a particular line of problematic code. Relates to #352 Signed-off-by: Eric Brown --- tests/functional/test_functional.py | 536 +------ tests/unit/blacklists/base_test_case.py | 33 + tests/unit/blacklists/test_cipher_call.py | 297 ++++ tests/unit/blacklists/test_cipher_modes.py | 57 + tests/unit/blacklists/test_eval_call.py | 44 + tests/unit/blacklists/test_ftplib_call.py | 29 + tests/unit/blacklists/test_ftplib_import.py | 22 + tests/unit/blacklists/test_httpoxy_import.py | 89 ++ tests/unit/blacklists/test_mark_safe_call.py | 30 + .../test_marshal_deserialize_call.py | 61 + tests/unit/blacklists/test_md5_call.py | 234 +++ tests/unit/blacklists/test_mktemp.py | 29 + tests/unit/blacklists/test_pickle_call.py | 280 ++++ tests/unit/blacklists/test_pickle_import.py | 54 + tests/unit/blacklists/test_pycrypto_import.py | 147 ++ .../blacklists/test_pycryptodome_import.py | 27 + tests/unit/blacklists/test_pyghmi_import.py | 33 + tests/unit/blacklists/test_random_call.py | 177 +++ tests/unit/blacklists/test_telnetlib_call.py | 29 + .../unit/blacklists/test_telnetlib_import.py | 22 + .../test_unverified_context_call.py | 39 + tests/unit/plugins/__init__.py | 0 tests/unit/plugins/base_test_case.py | 33 + tests/unit/plugins/test_app_debug.py | 71 + tests/unit/plugins/test_asserts.py | 23 + .../test_crypto_request_no_cert_validation.py | 497 ++++++ .../unit/plugins/test_django_sql_injection.py | 386 +++++ tests/unit/plugins/test_django_xss.py | 853 ++++++++++ tests/unit/plugins/test_exec.py | 21 + .../test_general_bad_file_permissions.py | 212 +++ .../test_general_bind_all_interfaces.py | 40 + .../test_general_hardcoded_password.py | 250 +++ .../plugins/test_general_hardcoded_tmp.py | 82 + .../test_hashlib_insecure_functions.py | 202 +++ tests/unit/plugins/test_injection_paramiko.py | 39 + tests/unit/plugins/test_injection_shell.py | 1393 +++++++++++++++++ tests/unit/plugins/test_injection_sql.py | 238 +++ tests/unit/plugins/test_injection_wildcard.py | 138 ++ tests/unit/plugins/test_insecure_ssl_tls.py | 453 ++++++ tests/unit/plugins/test_jinja2_templates.py | 87 + .../test_logging_config_insecure_listen.py | 38 + tests/unit/plugins/test_mako_templates.py | 62 + .../plugins/test_request_without_timeout.py | 347 ++++ .../unit/plugins/test_snmp_security_check.py | 93 ++ .../test_ssh_no_host_key_verification.py | 58 + .../unit/plugins/test_try_except_continue.py | 154 ++ tests/unit/plugins/test_try_except_pass.py | 155 ++ .../plugins/test_weak_cryptographic_key.py | 438 ++++++ tests/unit/plugins/test_yaml_load.py | 122 ++ 49 files changed, 8219 insertions(+), 535 deletions(-) create mode 100644 tests/unit/blacklists/base_test_case.py create mode 100644 tests/unit/blacklists/test_cipher_call.py create mode 100644 tests/unit/blacklists/test_cipher_modes.py create mode 100644 tests/unit/blacklists/test_eval_call.py create mode 100644 tests/unit/blacklists/test_ftplib_call.py create mode 100644 tests/unit/blacklists/test_ftplib_import.py create mode 100644 tests/unit/blacklists/test_httpoxy_import.py create mode 100644 tests/unit/blacklists/test_mark_safe_call.py create mode 100644 tests/unit/blacklists/test_marshal_deserialize_call.py create mode 100644 tests/unit/blacklists/test_md5_call.py create mode 100644 tests/unit/blacklists/test_mktemp.py create mode 100644 tests/unit/blacklists/test_pickle_call.py create mode 100644 tests/unit/blacklists/test_pickle_import.py create mode 100644 tests/unit/blacklists/test_pycrypto_import.py create mode 100644 tests/unit/blacklists/test_pycryptodome_import.py create mode 100644 tests/unit/blacklists/test_pyghmi_import.py create mode 100644 tests/unit/blacklists/test_random_call.py create mode 100644 tests/unit/blacklists/test_telnetlib_call.py create mode 100644 tests/unit/blacklists/test_telnetlib_import.py create mode 100644 tests/unit/blacklists/test_unverified_context_call.py create mode 100644 tests/unit/plugins/__init__.py create mode 100644 tests/unit/plugins/base_test_case.py create mode 100644 tests/unit/plugins/test_app_debug.py create mode 100644 tests/unit/plugins/test_asserts.py create mode 100644 tests/unit/plugins/test_crypto_request_no_cert_validation.py create mode 100644 tests/unit/plugins/test_django_sql_injection.py create mode 100644 tests/unit/plugins/test_django_xss.py create mode 100644 tests/unit/plugins/test_exec.py create mode 100644 tests/unit/plugins/test_general_bad_file_permissions.py create mode 100644 tests/unit/plugins/test_general_bind_all_interfaces.py create mode 100644 tests/unit/plugins/test_general_hardcoded_password.py create mode 100644 tests/unit/plugins/test_general_hardcoded_tmp.py create mode 100644 tests/unit/plugins/test_hashlib_insecure_functions.py create mode 100644 tests/unit/plugins/test_injection_paramiko.py create mode 100644 tests/unit/plugins/test_injection_shell.py create mode 100644 tests/unit/plugins/test_injection_sql.py create mode 100644 tests/unit/plugins/test_injection_wildcard.py create mode 100644 tests/unit/plugins/test_insecure_ssl_tls.py create mode 100644 tests/unit/plugins/test_jinja2_templates.py create mode 100644 tests/unit/plugins/test_logging_config_insecure_listen.py create mode 100644 tests/unit/plugins/test_mako_templates.py create mode 100644 tests/unit/plugins/test_request_without_timeout.py create mode 100644 tests/unit/plugins/test_snmp_security_check.py create mode 100644 tests/unit/plugins/test_ssh_no_host_key_verification.py create mode 100644 tests/unit/plugins/test_try_except_continue.py create mode 100644 tests/unit/plugins/test_try_except_pass.py create mode 100644 tests/unit/plugins/test_weak_cryptographic_key.py create mode 100644 tests/unit/plugins/test_yaml_load.py diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index bc868939..4f6d5105 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -98,104 +98,6 @@ def check_metrics(self, example_script, expect): expected = expect["issues"][criteria][rank] self.assertEqual(expected, m["_totals"][label]) - def test_binding(self): - """Test the bind-to-0.0.0.0 example.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - } - self.check_example("binding.py", expect) - - def test_crypto_md5(self): - """Test the `hashlib.md5` example.""" - if sys.version_info >= (3, 9): - expect = { - "SEVERITY": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 10, - "HIGH": 9, - }, - "CONFIDENCE": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 0, - "HIGH": 19, - }, - } - else: - expect = { - "SEVERITY": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 16, - "HIGH": 4, - }, - "CONFIDENCE": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 0, - "HIGH": 20, - }, - } - self.check_example("crypto-md5.py", expect) - - def test_ciphers(self): - """Test the `Crypto.Cipher` example.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 21}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 22}, - } - self.check_example("ciphers.py", expect) - - def test_cipher_modes(self): - """Test for insecure cipher modes.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - } - self.check_example("cipher-modes.py", expect) - - def test_eval(self): - """Test the `eval` example.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("eval.py", expect) - - def test_mark_safe(self): - """Test the `mark_safe` example.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - } - self.check_example("mark_safe.py", expect) - - def test_exec(self): - """Test the `exec` example.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - } - self.check_example("exec.py", expect) - - def test_hardcoded_passwords(self): - """Test for hard-coded passwords.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 14, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 14, "HIGH": 0}, - } - self.check_example("hardcoded-passwords.py", expect) - - def test_hardcoded_tmp(self): - """Test for hard-coded /tmp, /var/tmp, /dev/shm.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - } - self.check_example("hardcoded-tmp.py", expect) - def test_imports_aliases(self): """Test the `import X as Y` syntax.""" if sys.version_info >= (3, 9): @@ -236,22 +138,6 @@ def test_imports_function(self): } self.check_example("imports-function.py", expect) - def test_telnet_usage(self): - """Test for `import telnetlib` and Telnet.* calls.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - } - self.check_example("telnetlib.py", expect) - - 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}, - } - self.check_example("ftplib.py", expect) - def test_imports(self): """Test for dangerous imports.""" expect = { @@ -268,14 +154,6 @@ def test_imports_using_importlib(self): } self.check_example("imports-with-importlib.py", expect) - def test_mktemp(self): - """Test for `tempfile.mktemp`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 4, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 4}, - } - self.check_example("mktemp.py", expect) - def test_nonsense(self): """Test that a syntactically invalid module is skipped.""" self.run_example("nonsense.py") @@ -297,126 +175,6 @@ def test_subdirectory_okay(self): } self.check_example("init-py-test/subdirectory-okay.py", expect) - def test_os_chmod(self): - """Test setting file permissions.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 4, "HIGH": 8}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 11}, - } - self.check_example("os-chmod.py", expect) - - def test_os_exec(self): - """Test for `os.exec*`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 8, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 8, "HIGH": 0}, - } - self.check_example("os-exec.py", expect) - - def test_os_popen(self): - """Test for `os.popen`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 8, "MEDIUM": 0, "HIGH": 1}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 9}, - } - self.check_example("os-popen.py", expect) - - def test_os_spawn(self): - """Test for `os.spawn*`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 8, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 8, "HIGH": 0}, - } - self.check_example("os-spawn.py", expect) - - def test_os_startfile(self): - """Test for `os.startfile`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 3, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - } - self.check_example("os-startfile.py", expect) - - def test_os_system(self): - """Test for `os.system`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - } - self.check_example("os_system.py", expect) - - def test_pickle(self): - """Test for the `pickle` module.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 4}, - } - self.check_example("pickle_deserialize.py", expect) - - def test_dill(self): - """Test for the `dill` module.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 4}, - } - self.check_example("dill.py", expect) - - def test_shelve(self): - """Test for the `shelve` module.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 2, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("shelve_open.py", expect) - - def test_jsonpickle(self): - """Test for the `jsonpickle` module.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("jsonpickle.py", expect) - - def test_pandas_read_pickle(self): - """Test for the `pandas.read_pickle` module.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - } - self.check_example("pandas_read_pickle.py", expect) - - def test_popen_wrappers(self): - """Test the `popen2` and `commands` modules.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 7, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 7}, - } - self.check_example("popen_wrappers.py", expect) - - def test_random_module(self): - """Test for the `random` module.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 7, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 7}, - } - self.check_example("random_module.py", expect) - - def test_requests_ssl_verify_disabled(self): - """Test for the `requests` library skipping verification.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 18}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 18}, - } - self.check_example("requests-ssl-verify-disabled.py", expect) - - def test_requests_without_timeout(self): - """Test for the `requests` library missing timeouts.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 14, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 14, "MEDIUM": 0, "HIGH": 0}, - } - self.check_example("requests-missing-timeout.py", expect) - def test_skip(self): """Test `#nosec` and `#noqa` comments.""" expect = { @@ -433,24 +191,6 @@ def test_ignore_skip(self): } self.check_example("skip.py", expect, ignore_nosec=True) - def test_sql_statements(self): - """Test for SQL injection through string building.""" - expect = { - "SEVERITY": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 18, - "HIGH": 0, - }, - "CONFIDENCE": { - "UNDEFINED": 0, - "LOW": 8, - "MEDIUM": 10, - "HIGH": 0, - }, - } - self.check_example("sql_statements.py", expect) - def test_multiline_sql_statements(self): """ Test for SQL injection through string building using @@ -494,110 +234,6 @@ def test_multiline_sql_statements(self): self.check_example(example_file, expect) self.check_metrics(example_file, expect_stats) - def test_ssl_insecure_version(self): - """Test for insecure SSL protocol versions.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 13, "HIGH": 9}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 14, "HIGH": 9}, - } - self.check_example("ssl-insecure-version.py", expect) - - def test_subprocess_shell(self): - """Test for `subprocess.Popen` with `shell=True`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 21, "MEDIUM": 1, "HIGH": 11}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 0, "HIGH": 32}, - } - self.check_example("subprocess_shell.py", expect) - - def test_urlopen(self): - """Test for dangerous URL opening.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 8, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 8}, - } - self.check_example("urlopen.py", expect) - - def test_wildcard_injection(self): - """Test for wildcard injection in shell commands.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 10, "MEDIUM": 0, "HIGH": 4}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 5, "HIGH": 9}, - } - self.check_example("wildcard-injection.py", expect) - - def test_django_sql_injection(self): - """Test insecure extra functions on Django.""" - - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 11, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 11, "HIGH": 0}, - } - self.check_example("django_sql_injection_extra.py", expect) - - def test_django_sql_injection_raw(self): - """Test insecure raw functions on Django.""" - - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 4, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 4, "HIGH": 0}, - } - self.check_example("django_sql_injection_raw.py", expect) - - def test_yaml(self): - """Test for `yaml.load`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 2, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - } - self.check_example("yaml_load.py", expect) - - def test_host_key_verification(self): - """Test for ignoring host key verification.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 2, "HIGH": 0}, - } - self.check_example("no_host_key_verification.py", expect) - - def test_jinja2_templating(self): - """Test jinja templating for potential XSS bugs.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 5}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 2, "HIGH": 3}, - } - self.check_example("jinja2_templating.py", expect) - - def test_mako_templating(self): - """Test Mako templates for XSS.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("mako_templating.py", expect) - - def test_django_xss_secure(self): - """Test false positives for Django XSS""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 0}, - } - self.b_mgr.b_ts = b_test_set.BanditTestSet( - config=self.b_mgr.b_conf, profile={"exclude": ["B308"]} - ) - self.check_example("mark_safe_secure.py", expect) - - def test_django_xss_insecure(self): - """Test for Django XSS via django.utils.safestring""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 29, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 29}, - } - self.b_mgr.b_ts = b_test_set.BanditTestSet( - config=self.b_mgr.b_conf, profile={"exclude": ["B308"]} - ) - self.check_example("mark_safe_insecure.py", expect) - def test_xml(self): """Test xml vulnerabilities.""" expect = { @@ -654,17 +290,7 @@ def test_xml(self): } self.check_example("xml_sax.py", expect) - def test_httpoxy(self): - """Test httpoxy vulnerability.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - } - self.check_example("httpoxy_cgihandler.py", expect) - self.check_example("httpoxy_twisted_script.py", expect) - self.check_example("httpoxy_twisted_directory.py", expect) - - def test_asserts(self): + def test_skips(self): """Test catching the use of assert.""" test = next( x @@ -693,66 +319,6 @@ def test_asserts(self): } self.check_example("assert.py", expect) - def test_paramiko_injection(self): - """Test paramiko command execution.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - } - self.check_example("paramiko_injection.py", expect) - - def test_partial_path(self): - """Test process spawning with partial file paths.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 11, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 11}, - } - self.check_example("partial_path_process.py", expect) - - def test_try_except_continue(self): - """Test try, except, continue detection.""" - test = next( - x - for x in self.b_mgr.b_ts.tests["ExceptHandler"] - if x.__name__ == "try_except_continue" - ) - - test._config = {"check_typed_exception": True} - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 3, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("try_except_continue.py", expect) - - test._config = {"check_typed_exception": False} - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 2, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - } - self.check_example("try_except_continue.py", expect) - - def test_try_except_pass(self): - """Test try, except pass detection.""" - test = next( - x - for x in self.b_mgr.b_ts.tests["ExceptHandler"] - if x.__name__ == "try_except_pass" - ) - - test._config = {"check_typed_exception": True} - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 3, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("try_except_pass.py", expect) - - test._config = {"check_typed_exception": False} - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 2, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - } - self.check_example("try_except_pass.py", expect) - def test_metric_gathering(self): expect = { "nosec": 2, @@ -767,14 +333,6 @@ def test_metric_gathering(self): } self.check_metrics("imports.py", expect) - def test_weak_cryptographic_key(self): - """Test for weak key sizes.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 8, "HIGH": 8}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 16}, - } - self.check_example("weak_cryptographic_key_sizes.py", expect) - def test_multiline_code(self): """Test issues in multiline statements return code as expected.""" self.run_example("multiline_statement.py") @@ -815,13 +373,6 @@ def test_code_line_numbers(self): self.assertEqual("%i " % (lineno), code_lines[1][:2]) self.assertEqual("%i " % (lineno + 1), code_lines[2][:2]) - def test_flask_debug_true(self): - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - } - self.check_example("flask_debug.py", expect) - def test_nosec(self): expect = { "SEVERITY": {"UNDEFINED": 0, "LOW": 5, "MEDIUM": 0, "HIGH": 0}, @@ -863,88 +414,3 @@ def test_baseline_filter(self): self.run_example("flask_debug.py") self.assertEqual(1, len(self.b_mgr.baseline)) self.assertEqual({}, self.b_mgr.get_issue_list()) - - def test_unverified_context(self): - """Test for `ssl._create_unverified_context`.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 1}, - } - self.check_example("unverified_context.py", expect) - - def test_hashlib_new_insecure_functions(self): - """Test insecure hash functions created by `hashlib.new`.""" - if sys.version_info >= (3, 9): - expect = { - "SEVERITY": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 0, - "HIGH": 9, - }, - "CONFIDENCE": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 0, - "HIGH": 9, - }, - } - else: - expect = { - "SEVERITY": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 10, - "HIGH": 0, - }, - "CONFIDENCE": { - "UNDEFINED": 0, - "LOW": 0, - "MEDIUM": 0, - "HIGH": 10, - }, - } - self.check_example("hashlib_new_insecure_functions.py", expect) - - def test_blacklist_pycrypto(self): - """Test importing pycrypto module""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2}, - } - self.check_example("pycrypto.py", expect) - - def test_no_blacklist_pycryptodome(self): - """Test importing pycryptodome module - - make sure it's no longer blacklisted - """ - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 0}, - } - self.check_example("pycryptodome.py", expect) - - def test_blacklist_pyghmi(self): - """Test calling pyghmi methods""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 0, "HIGH": 1}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 1}, - } - self.check_example("pyghmi.py", expect) - - def test_snmp_security_check(self): - """Test insecure and weak crypto usage of SNMP.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 3, "HIGH": 0}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3}, - } - self.check_example("snmp.py", expect) - - def test_tarfile_unsafe_members(self): - """Test insecure usage of tarfile.""" - expect = { - "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 2, "HIGH": 1}, - "CONFIDENCE": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 2, "HIGH": 1}, - } - self.check_example("tarfile_extractall.py", expect) diff --git a/tests/unit/blacklists/base_test_case.py b/tests/unit/blacklists/base_test_case.py new file mode 100644 index 00000000..536b7906 --- /dev/null +++ b/tests/unit/blacklists/base_test_case.py @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: Apache-2.0 +import testtools + +from bandit.core import config +from bandit.core import manager +from bandit.core import meta_ast +from bandit.core import metrics +from bandit.core import node_visitor +from bandit.core import test_set + + +class BaseTestCase(testtools.TestCase): + def setUp(self, test_ids): + super().setUp() + self.b_config = config.BanditConfig() + self.b_manager = manager.BanditManager(self.b_config, "file") + issue_metrics = metrics.Metrics() + issue_metrics.begin("test.py") + self.visitor = node_visitor.BanditNodeVisitor( + "test.py", + None, + metaast=meta_ast.BanditMetaAst(), + testset=test_set.BanditTestSet( + self.b_config, + profile={ + "include": test_ids, + "exclude": [], + }, + ), + debug=False, + nosec_lines={}, + metrics=issue_metrics, + ) diff --git a/tests/unit/blacklists/test_cipher_call.py b/tests/unit/blacklists/test_cipher_call.py new file mode 100644 index 00000000..58a4474a --- /dev/null +++ b/tests/unit/blacklists/test_cipher_call.py @@ -0,0 +1,297 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class CipherCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B304"]) + + def test_crypto_cipher_arc2_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Cipher import ARC2 as pycrypto_arc2 + from Crypto import Random + key = b'Sixteen byte key' + iv = Random.new().read(pycrypto_arc2.block_size) + pycrypto_arc2.new(key, pycrypto_arc2.MODE_CFB, iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_cipher_arc4_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Cipher import ARC4 as pycrypto_arc4 + from Crypto import Random + key = b'Very long and confidential key' + nonce = Random.new().read(16) + tempkey = SHA.new(key+nonce).digest() + pycrypto_arc4.new(tempkey) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_cipher_blowfish_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Cipher import Blowfish as pycrypto_blowfish + from Crypto import Random + key = b'An arbitrarily long key' + bs = pycrypto_blowfish.block_size + iv = Random.new().read(bs) + pycrypto_blowfish.new(key, pycrypto_blowfish.MODE_CBC, iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_cipher_des_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Cipher import DES as pycrypto_des + from Crypto import Random + nonce = Random.new().read(pycrypto_des.block_size / 2) + ctr = Counter.new(pycrypto_des.block_size * 8 / 2, prefix=nonce) + pycrypto_des.new(key, pycrypto_des.MODE_CTR, counter=ctr) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_cipher_xor_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Cipher import XOR as pycrypto_xor + key = b'Super secret key' + pycrypto_xor.new(key) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_cipher_arc2_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Cipher import ARC2 as pycryptodomex_arc2 + from Crypto import Random + key = b'Sixteen byte key' + iv = Random.new().read(pycryptodomex_arc2.block_size) + pycryptodomex_arc2.new(key, pycryptodomex_arc2.MODE_CFB, iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_cipher_arc4_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Cipher import ARC4 as pycryptodomex_arc4 + from Cryptodome import Random + key = b'Very long and confidential key' + nonce = Random.new().read(16) + tempkey = SHA.new(key + nonce).digest() + pycryptodomex_arc4.new(tempkey) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_cipher_blowfish_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Cipher import Blowfish as pycryptodomex_blowfish + from Cryptodome import Random + key = b'An arbitrarily long key' + bs = pycryptodomex_blowfish.block_size + iv = Random.new().read(bs) + mode = pycryptodomex_blowfish.MODE_CBC + pycryptodomex_blowfish.new(key, mode, iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(8, issue.lineno) + self.assertEqual([8], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_cipher_des_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Cipher import DES as pycryptodomex_des + from Cryptodome import Random + nonce = Random.new().read(pycryptodomex_des.block_size / 2) + ctr = Counter.new(pycryptodomex_des.block_size * 8/2, prefix=nonce) + pycryptodomex_des.new(key, pycryptodomex_des.MODE_CTR, counter=ctr) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_cipher_xor_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Cipher import XOR as pycryptodomex_xor + key = b'Super secret key' + pycryptodomex_xor.new(key) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_ciphers_algorithms_arc4(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat.primitives.ciphers import Cipher + from cryptography.hazmat.primitives.ciphers import algorithms + from cryptography.hazmat.backends import default_backend + key = b'Super secret key' + Cipher( + algorithms.ARC4(key), + mode=None, + backend=default_backend() + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_cryptography_ciphers_algorithms_blowfish(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat.primitives.ciphers import Cipher + from cryptography.hazmat.primitives.ciphers import algorithms + from cryptography.hazmat.backends import default_backend + key = b'Super secret key' + Cipher( + algorithms.Blowfish(key), + mode=None, + backend=default_backend() + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_cryptography_ciphers_algorithms_idea(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat.primitives.ciphers import Cipher + from cryptography.hazmat.primitives.ciphers import algorithms + from cryptography.hazmat.backends import default_backend + key = b'Super secret key' + Cipher( + algorithms.IDEA(key), + mode=None, + backend=default_backend(), + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B304", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(4, issue.col_offset) diff --git a/tests/unit/blacklists/test_cipher_modes.py b/tests/unit/blacklists/test_cipher_modes.py new file mode 100644 index 00000000..27adfd2c --- /dev/null +++ b/tests/unit/blacklists/test_cipher_modes.py @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class CipherModesTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B305"]) + + def test_cipher_mode_ecb(self): + fdata = textwrap.dedent( + """ + import os + from cryptography.hazmat.primitives.ciphers.modes import ECB + iv = os.urandom(16) + ECB(iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B305", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cipher_mode_ctr(self): + fdata = textwrap.dedent( + """ + import os + from cryptography.hazmat.primitives.ciphers import algorithms + from cryptography.hazmat.primitives.ciphers import modes + key = os.urandom(32) + iv = os.urandom(16) + algorithms.AES.new(key, modes.CTR, iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cipher_mode_cbc(self): + fdata = textwrap.dedent( + """ + import os + from cryptography.hazmat.primitives.ciphers.modes import CBC + iv = os.urandom(16) + CBC(iv) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/blacklists/test_eval_call.py b/tests/unit/blacklists/test_eval_call.py new file mode 100644 index 00000000..19a27c7d --- /dev/null +++ b/tests/unit/blacklists/test_eval_call.py @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class EvalCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B307"]) + + def test_eval_call(self): + fdata = textwrap.dedent( + """ + import os + eval("os.getcwd()") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B307", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_eval_method(self): + fdata = textwrap.dedent( + """ + class Test(object): + def eval(self): + print("hi") + def foo(self): + self.eval() + + Test().eval() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/blacklists/test_ftplib_call.py b/tests/unit/blacklists/test_ftplib_call.py new file mode 100644 index 00000000..4444cbff --- /dev/null +++ b/tests/unit/blacklists/test_ftplib_call.py @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class FtplibCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B321"]) + + def test_call_ftplib(self): + fdata = textwrap.dedent( + """ + from ftplib import FTP + FTP('ftp.debian.org') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B321", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_ftplib_import.py b/tests/unit/blacklists/test_ftplib_import.py new file mode 100644 index 00000000..0653923a --- /dev/null +++ b/tests/unit/blacklists/test_ftplib_import.py @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class FtplibImportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B402"]) + + def test_import_ftplib(self): + fdata = "from ftplib import FTP" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B402", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_httpoxy_import.py b/tests/unit/blacklists/test_httpoxy_import.py new file mode 100644 index 00000000..43ce6b4c --- /dev/null +++ b/tests/unit/blacklists/test_httpoxy_import.py @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class HttpoxyImportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B412"]) + + def test_wsgiref_handlers(self): + fdata = textwrap.dedent( + """ + import requests + from wsgiref import handlers + + def application(environ, start_response): + r = requests.get('https://192.168.0.42/api/foobar', timeout=30) + start_response('200 OK', [('Content-Type', 'text/plain')]) + return [r.content] + + if __name__ == '__main__': + wsgiref.handlers.CGIHandler().run(application) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B412", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_ACCESS_CONTROL, issue.cwe.id) + self.assertEqual(11, issue.lineno) + self.assertEqual([11], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_twisted_web_twcgi_cgiscript(self): + fdata = textwrap.dedent( + """ + from twisted.internet import reactor + from twisted.web import static, server, twcgi + + root = static.File("/root") + root.putChild( + "login.cgi", + twcgi.CGIScript("/var/www/cgi-bin/login.py"), + ) + reactor.listenTCP(80, server.Site(root)) + reactor.run() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B412", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_ACCESS_CONTROL, issue.cwe.id) + self.assertEqual(8, issue.lineno) + self.assertEqual([8], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_twisted_web_twcgi_cgidirectory(self): + fdata = textwrap.dedent( + """ + from twisted.internet import reactor + from twisted.web import static, server, twcgi + + root = static.File("/root") + root.putChild( + "cgi-bin", + twcgi.CGIDirectory("/var/www/cgi-bin"), + ) + reactor.listenTCP(80, server.Site(root)) + reactor.run() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B412", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_ACCESS_CONTROL, issue.cwe.id) + self.assertEqual(8, issue.lineno) + self.assertEqual([8], issue.linerange) + self.assertEqual(4, issue.col_offset) diff --git a/tests/unit/blacklists/test_mark_safe_call.py b/tests/unit/blacklists/test_mark_safe_call.py new file mode 100644 index 00000000..dd3ad641 --- /dev/null +++ b/tests/unit/blacklists/test_mark_safe_call.py @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class MarkSafeTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B308"]) + + def test_django_utils_safestring_mark_safe(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + + safestring.mark_safe('Hello World') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B308", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.XSS, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_marshal_deserialize_call.py b/tests/unit/blacklists/test_marshal_deserialize_call.py new file mode 100644 index 00000000..d35ba0e4 --- /dev/null +++ b/tests/unit/blacklists/test_marshal_deserialize_call.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class MarshalDeserializeCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B302"]) + + def test_marshal_load(self): + fdata = textwrap.dedent( + """ + import marshal + import tempfile + + file_obj = tempfile.TemporaryFile() + marshal.dump(range(5), file_obj) + file_obj.seek(0) + marshal.load(file_obj) + file_obj.close() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B302", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, + issue.cwe.id, + ) + self.assertEqual(8, issue.lineno) + self.assertEqual([8], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_marshal_loads(self): + fdata = textwrap.dedent( + """ + import marshal + + serialized = marshal.dumps({'a': 1}) + marshal.loads(serialized) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B302", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, + issue.cwe.id, + ) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_md5_call.py b/tests/unit/blacklists/test_md5_call.py new file mode 100644 index 00000000..76d3f2f6 --- /dev/null +++ b/tests/unit/blacklists/test_md5_call.py @@ -0,0 +1,234 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class Md5CallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B303"]) + + def test_hashlib_md5(self): + fdata = textwrap.dedent( + """ + import hashlib + hashlib.md5(1) + """ + ) + self.visitor.process(fdata) + if sys.version_info >= (3, 9): + self.assertEqual(0, len(self.visitor.tester.results)) + else: + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_sha1(self): + fdata = textwrap.dedent( + """ + import hashlib + hashlib.sha1(1) + """ + ) + self.visitor.process(fdata) + if sys.version_info >= (3, 9): + self.assertEqual(0, len(self.visitor.tester.results)) + else: + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_hash_md2_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Hash import MD2 as pycrypto_md2 + pycrypto_md2.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_hash_md4_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Hash import MD4 as pycrypto_md4 + pycrypto_md4.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_hash_md5_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Hash import MD5 as pycrypto_md5 + pycrypto_md5.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_crypto_hash_sha_new(self): + fdata = textwrap.dedent( + """ + from Crypto.Hash import SHA as pycrypto_sha + pycrypto_sha.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_hash_md2_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Hash import MD2 as pycryptodomex_md2 + pycryptodomex_md2.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_hash_md4_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Hash import MD4 as pycryptodomex_md4 + pycryptodomex_md4.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_hash_md5_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Hash import MD5 as pycryptodomex_md5 + pycryptodomex_md5.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptodome_hash_sha_new(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Hash import SHA as pycryptodomex_sha + pycryptodomex_sha.new() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_hazmat_primitives_hashes_md5(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat.primitives import hashes + hashes.MD5() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_hazmat_primitives_hashes_sha1(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat.primitives import hashes + hashes.SHA1() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B303", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_mktemp.py b/tests/unit/blacklists/test_mktemp.py new file mode 100644 index 00000000..d9116e6e --- /dev/null +++ b/tests/unit/blacklists/test_mktemp.py @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class MktempTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B306"]) + + def test_mktemp(self): + fdata = textwrap.dedent( + """ + from tempfile import mktemp + mktemp('foo') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B306", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSECURE_TEMP_FILE, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_pickle_call.py b/tests/unit/blacklists/test_pickle_call.py new file mode 100644 index 00000000..fd124b02 --- /dev/null +++ b/tests/unit/blacklists/test_pickle_call.py @@ -0,0 +1,280 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class PickleCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B301"]) + + def test_pickle_loads(self): + fdata = textwrap.dedent( + """ + import pickle + pick = pickle.dumps({'a': 'b', 'c': 'd'}) + pickle.loads(pick) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pickle_load(self): + fdata = textwrap.dedent( + """ + import io + import pickle + file_obj = io.BytesIO() + pickle.dump([1, 2, '3'], file_obj) + file_obj.seek(0) + pickle.load(file_obj) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pickle_unpickler(self): + fdata = textwrap.dedent( + """ + import io + import pickle + file_obj = io.BytesIO() + pickle.dump([1, 2, '3'], file_obj) + file_obj.seek(0) + pickle.Unpickler(file_obj) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_dill_loads(self): + fdata = textwrap.dedent( + """ + import dill + pick = dill.dumps({'a': 'b', 'c': 'd'}) + dill.loads(pick) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_dill_load(self): + fdata = textwrap.dedent( + """ + import io + import dill + file_obj = io.BytesIO() + dill.dump([1, 2, '3'], file_obj) + file_obj.seek(0) + dill.load(file_obj) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_dill_unpickler(self): + fdata = textwrap.dedent( + """ + import io + import dill + file_obj = io.BytesIO() + dill.dump([1, 2, '3'], file_obj) + file_obj.seek(0) + dill.Unpickler(file_obj) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_shelve_open(self): + fdata = textwrap.dedent( + """ + import os + import shelve + with tempfile.TemporaryDirectory() as d: + filename = os.path.join(d, 'shelf') + shelve.open(filename) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_shelve_dbfilenameshelf(self): + fdata = textwrap.dedent( + """ + import os + import shelve + with tempfile.TemporaryDirectory() as d: + filename = os.path.join(d, 'shelf') + shelve.DbfilenameShelf(filename) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_jsonpickle_decode(self): + fdata = textwrap.dedent( + """ + import jsonpickle + pick = jsonpickle.encode({'a': 'b', 'c': 'd'}) + jsonpickle.decode(pick) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_jsonpickle_unpickler_decode(self): + fdata = textwrap.dedent( + """ + import jsonpickle + pick = jsonpickle.encode({'a': 'b', 'c': 'd'}) + jsonpickle.unpickler.decode(pick) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_jsonpickle_unpickler_unpickler(self): + fdata = textwrap.dedent( + """ + import jsonpickle + pick = jsonpickle.encode({'a': 'b', 'c': 'd'}) + jsonpickle.unpickler.Unpickler().restore(pick) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pandas_read_pickle(self): + fdata = textwrap.dedent( + """ + import pandas + df = pandas.DataFrame({"col_A": [1, 2]}) + pick = pickle.dumps(df) + pandas.read_pickle(pick) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B301", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_pickle_import.py b/tests/unit/blacklists/test_pickle_import.py new file mode 100644 index 00000000..aba2baee --- /dev/null +++ b/tests/unit/blacklists/test_pickle_import.py @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: Apache-2.0 +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class PicklemportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B403"]) + + def test_import_pickle(self): + fdata = "import pickle" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B403", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_dill(self): + fdata = "import dill" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B403", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_shelve(self): + fdata = "import shelve" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B403", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.DESERIALIZATION_OF_UNTRUSTED_DATA, issue.cwe.id + ) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_pycrypto_import.py b/tests/unit/blacklists/test_pycrypto_import.py new file mode 100644 index 00000000..a86f7cc2 --- /dev/null +++ b/tests/unit/blacklists/test_pycrypto_import.py @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class PycryptoImportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B413"]) + + def test_import_crypto_cipher(self): + fdata = textwrap.dedent( + """ + from Crypto.Cipher import AES + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_hash(self): + fdata = textwrap.dedent( + """ + from Crypto import Hash + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_io(self): + fdata = textwrap.dedent( + """ + from Crypto import IO + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_protocol(self): + fdata = textwrap.dedent( + """ + from Crypto import Protocol + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_publickey(self): + fdata = textwrap.dedent( + """ + from Crypto import PublicKey + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_random(self): + fdata = textwrap.dedent( + """ + from Crypto import Random + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_signature(self): + fdata = textwrap.dedent( + """ + from Crypto import Signature + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_import_crypto_util(self): + fdata = textwrap.dedent( + """ + from Crypto import Util + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B413", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_pycryptodome_import.py b/tests/unit/blacklists/test_pycryptodome_import.py new file mode 100644 index 00000000..3e97a193 --- /dev/null +++ b/tests/unit/blacklists/test_pycryptodome_import.py @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +from tests.unit.blacklists import base_test_case + + +class PycryptodomeImportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B414"]) + + def test_import_cryptodome(self): + fdata = textwrap.dedent( + """ + from Cryptodome.Cipher import AES + from Cryptodome import Random + + from . import CryptoMaterialsCacheEntry + + def test_pycrypto(): + key = b'Sixteen byte key' + iv = Random.new().read(AES.block_size) + cipher = pycrypto_arc2.new(key, AES.MODE_CFB, iv) + factory = CryptoMaterialsCacheEntry() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/blacklists/test_pyghmi_import.py b/tests/unit/blacklists/test_pyghmi_import.py new file mode 100644 index 00000000..9d1bcf69 --- /dev/null +++ b/tests/unit/blacklists/test_pyghmi_import.py @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class PyghmiImportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B415"]) + + def test_import_pyghmi(self): + fdata = textwrap.dedent( + """ + from pyghmi.ipmi import command + cmd = command.Command( + bmc="bmc", + userid="userid", + password="ZjE4ZjI0NTE4YmI2NGJjZDliOGY3ZmJiY2UyN2IzODQK" + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B415", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_random_call.py b/tests/unit/blacklists/test_random_call.py new file mode 100644 index 00000000..61b586de --- /dev/null +++ b/tests/unit/blacklists/test_random_call.py @@ -0,0 +1,177 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class RandomCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B311"]) + + def test_random_random(self): + fdata = textwrap.dedent( + """ + import random + random.random() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_random_randrange(self): + fdata = textwrap.dedent( + """ + import random + random.randrange() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_random_randint(self): + fdata = textwrap.dedent( + """ + import random + random.randint() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_random_choice(self): + fdata = textwrap.dedent( + """ + import random + random.choice() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_random_choices(self): + fdata = textwrap.dedent( + """ + import random + random.choices() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_random_uniform(self): + fdata = textwrap.dedent( + """ + import random + random.uniform() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_random_triangular(self): + fdata = textwrap.dedent( + """ + import random + random.triangular() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B311", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.INSUFFICIENT_RANDOM_VALUES, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_random(self): + fdata = textwrap.dedent( + """ + import os + os.urandom() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_random_systemrandom(self): + fdata = textwrap.dedent( + """ + import random + random.SystemRandom() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_unknown_random(self): + fdata = textwrap.dedent( + """ + import random + random() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_somelib_random(self): + fdata = textwrap.dedent( + """ + import somelib + somelib.a.random() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/blacklists/test_telnetlib_call.py b/tests/unit/blacklists/test_telnetlib_call.py new file mode 100644 index 00000000..d3856978 --- /dev/null +++ b/tests/unit/blacklists/test_telnetlib_call.py @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class TelnetlibCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B312"]) + + def test_call_telnetlib(self): + fdata = textwrap.dedent( + """ + import telnetlib + telnetlib.Telnet('localhost') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B312", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_telnetlib_import.py b/tests/unit/blacklists/test_telnetlib_import.py new file mode 100644 index 00000000..c79f3fb7 --- /dev/null +++ b/tests/unit/blacklists/test_telnetlib_import.py @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class TelnetlibImportTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B401"]) + + def test_import_telnetlib(self): + fdata = "import telnetlib" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B401", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/blacklists/test_unverified_context_call.py b/tests/unit/blacklists/test_unverified_context_call.py new file mode 100644 index 00000000..75486292 --- /dev/null +++ b/tests/unit/blacklists/test_unverified_context_call.py @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.blacklists import base_test_case + + +class UnverifiedContextCallTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B323"]) + + def test_create_unverified_context(self): + fdata = textwrap.dedent( + """ + import ssl + ssl._create_unverified_context() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B323", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_create_default_context(self): + fdata = textwrap.dedent( + """ + import ssl + ssl.create_default_context() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/__init__.py b/tests/unit/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/plugins/base_test_case.py b/tests/unit/plugins/base_test_case.py new file mode 100644 index 00000000..f1ce5248 --- /dev/null +++ b/tests/unit/plugins/base_test_case.py @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: Apache-2.0 +import testtools + +from bandit.core import config +from bandit.core import manager +from bandit.core import meta_ast +from bandit.core import metrics +from bandit.core import node_visitor +from bandit.core import test_set + + +class BaseTestCase(testtools.TestCase): + def setUp(self, test_ids): + super().setUp() + b_config = config.BanditConfig() + self.b_manager = manager.BanditManager(b_config, "file") + issue_metrics = metrics.Metrics() + issue_metrics.begin("test.py") + self.visitor = node_visitor.BanditNodeVisitor( + "test.py", + None, + metaast=meta_ast.BanditMetaAst(), + testset=test_set.BanditTestSet( + b_config, + profile={ + "include": test_ids, + "exclude": [], + }, + ), + debug=False, + nosec_lines={}, + metrics=issue_metrics, + ) diff --git a/tests/unit/plugins/test_app_debug.py b/tests/unit/plugins/test_app_debug.py new file mode 100644 index 00000000..5ea248ab --- /dev/null +++ b/tests/unit/plugins/test_app_debug.py @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class FlaskDebugTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B201"]) + + def test_app_run_debug_true(self): + fdata = textwrap.dedent( + """ + from flask import Flask + app = Flask(__name__) + app.run(debug=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.CODE_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_app_run_debug_false(self): + fdata = textwrap.dedent( + """ + from flask import Flask + app = Flask(__name__) + app.run(debug=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_app_run(self): + fdata = textwrap.dedent( + """ + from flask import Flask + app = Flask(__name__) + app.run() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_app_run_no_import(self): + fdata = textwrap.dedent( + """ + app = Flask(__name__) + app.run(debug=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_unrelated_run(self): + fdata = textwrap.dedent( + """ + from flask import Flask + run(debug=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_asserts.py b/tests/unit/plugins/test_asserts.py new file mode 100644 index 00000000..5be2f6c7 --- /dev/null +++ b/tests/unit/plugins/test_asserts.py @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class AssertsTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B101"]) + + def test_asserts(self): + fdata = "assert True" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_crypto_request_no_cert_validation.py b/tests/unit/plugins/test_crypto_request_no_cert_validation.py new file mode 100644 index 00000000..9b710d44 --- /dev/null +++ b/tests/unit/plugins/test_crypto_request_no_cert_validation.py @@ -0,0 +1,497 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class CryptoRequestNoCertValidationTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B501"]) + + def test_requests_get_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.get('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_get_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.get('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_post_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.post('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_post_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.post('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_put_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.put('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_put_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.put('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_delete_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.delete('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_delete_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.delete('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_patch_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.patch('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_patch_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.patch('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_options_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.options('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_options_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.options('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_head_verify_true(self): + fdata = textwrap.dedent( + """ + import requests + requests.head('https://example.com', timeout=30, verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_head_verify_false(self): + fdata = textwrap.dedent( + """ + import requests + requests.head('https://example.com', timeout=30, verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_request_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.request('GET', 'https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_request_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.request('GET', 'https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_get_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.get('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_get_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.get('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_options_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.options('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_options_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.options('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_head_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.head('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_head_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.head('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_post_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.post('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_post_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.post('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_put_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.put('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_put_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.put('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_patch_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.patch('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_patch_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.patch('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_delete_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.delete('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_delete_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.delete('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_stream_verify_true(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.stream('https://example.com', verify=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_stream_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.stream('https://example.com', verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_client_default(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.Client() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_client_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.Client(verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_httpx_asyncclient_default(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.AsyncClient() + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_httpx_asyncclient_verify_false(self): + fdata = textwrap.dedent( + """ + import httpx + httpx.AsyncClient(verify=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_django_sql_injection.py b/tests/unit/plugins/test_django_sql_injection.py new file mode 100644 index 00000000..90bd8911 --- /dev/null +++ b/tests/unit/plugins/test_django_sql_injection.py @@ -0,0 +1,386 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class DjangoSqlInjectionTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B610", "B611"]) + + def test_django_user_objects_filter_extra_select_where_tables(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + select={'test': 'secure'}, + where=['secure'], + tables=['secure'] + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_user_objects_filter_extra_dict(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra({'test': 'secure'}) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_user_objects_filter_extra_select_dict(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + select={'test': 'secure'} + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_user_objects_filter_extra_where(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra(where=['secure']) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_user_objects_filter_extra_dict_obj(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + dict(could_be='insecure') + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_select_dict_obj(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + select=dict(could_be='insecure') + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_select_query_var(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + query = ('"username") AS "username", * FROM "auth_user" ' + 'WHERE 1=1 OR "username"=? --') + User.objects.filter(username='admin').extra(select={'test': query}) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_select_dict_str_sub(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + select={'test': '%secure' % 'nos'} + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_select_dict_str_format(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + select={'test': '{}secure'.format('nos')} + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_where_var(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + where_var = ['1=1) OR 1=1 AND (1=1'] + User.objects.filter(username='admin').extra(where=where_var) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_where_str(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + where_str = '1=1) OR 1=1 AND (1=1' + User.objects.filter(username='admin').extra(where=[where_str]) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_where_str_sub(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + where=['%secure' % 'nos'] + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_where_str_format(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + User.objects.filter(username='admin').extra( + where=['{}secure'.format('no')] + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_tables_var(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + tables_var = [ + 'django_content_type" WHERE "auth_user"."username"="admin' + ] + User.objects.all().extra(tables=tables_var).distinct() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_filter_extra_tables_str(self): + fdata = textwrap.dedent( + """ + from django.contrib.auth.models import User + tables_str = ('django_content_type" WHERE ' + '"auth_user"."username"="admin') + User.objects.all().extra(tables=[tables_str]).distinct() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B610", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_user_objects_annotate_rawsql(self): + fdata = textwrap.dedent( + """ + from django.db.models.expressions import RawSQL + from django.contrib.auth.models import User + User.objects.annotate(val=RawSQL('secure', [])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_user_objects_annotate_rawsql_str_sub(self): + fdata = textwrap.dedent( + """ + from django.db.models.expressions import RawSQL + from django.contrib.auth.models import User + User.objects.annotate(val=RawSQL('%secure' % 'nos', [])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B611", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(26, issue.col_offset) + + def test_django_user_objects_annotate_rawsql_str_format(self): + fdata = textwrap.dedent( + """ + from django.db.models.expressions import RawSQL + from django.contrib.auth.models import User + User.objects.annotate(val=RawSQL('{}secure'.format('no'), [])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B611", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(26, issue.col_offset) + + def test_django_user_objects_annotate_rawsql_raw(self): + fdata = textwrap.dedent( + """ + from django.db.models.expressions import RawSQL + from django.contrib.auth.models import User + raw = ('"username") AS "val" FROM "auth_user" WHERE' + ' "username"="admin" --') + User.objects.annotate(val=RawSQL(raw, [])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B611", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(26, issue.col_offset) + + def test_django_user_objects_annotate_rawsql_raw_sub(self): + fdata = textwrap.dedent( + """ + from django.db.models.expressions import RawSQL + from django.contrib.auth.models import User + raw = '"username") AS "val" FROM "auth_user"' \ + ' WHERE "username"="admin" OR 1=%s --' + User.objects.annotate(val=RawSQL(raw, [0])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B611", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(26, issue.col_offset) diff --git a/tests/unit/plugins/test_django_xss.py b/tests/unit/plugins/test_django_xss.py new file mode 100644 index 00000000..472d31c3 --- /dev/null +++ b/tests/unit/plugins/test_django_xss.py @@ -0,0 +1,853 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class DjangoXssTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B703"]) + + def test_django_utils_safestring_mark_safe(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + safestring.mark_safe('secure') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_safestring_safetext(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + safestring.SafeText('secure') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_safestring_safeunicode(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + safestring.SafeUnicode('secure') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_safestring_safestring(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + safestring.SafeString('secure') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_safestring_safebytes(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + safestring.SafeBytes('secure') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_var(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + my_secure_str = 'Hello World' + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_tuple_var(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + my_secure_str, _ = ('Hello World', '') + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_var_var(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + my_secure_str, _ = ('Hello World', '') + also_secure_str = my_secure_str + safestring.mark_safe(also_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_func(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def try_secure(): + try: + my_secure_str = 'Secure' + except Exception: + my_secure_str = 'Secure' + else: + my_secure_str = 'Secure' + finally: + my_secure_str = 'Secure' + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_format_secure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def format_secure(): + safestring.mark_safe('{}'.format('secure')) + my_secure_str = 'secure' + safestring.mark_safe('{}'.format(my_secure_str)) + safestring.mark_safe('{} {}'.format(my_secure_str, 'a')) + safestring.mark_safe( + '{} {}'.format(*[my_secure_str, 'a']) + ) + my_secure_str = '{}'.format(my_secure_str) + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_percent_secure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def percent_secure(): + safestring.mark_safe('%s' % 'secure') + my_secure_str = 'secure' + safestring.mark_safe('%s' % my_secure_str) + safestring.mark_safe('%s %s' % (my_secure_str, 'a')) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_with_secure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def with_secure(path): + with open(path) as f: + safestring.mark_safe('Secure') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_loop_secure(self): + fdata = textwrap.dedent( + """ + import os + from django.utils import safestring + def loop_secure(): + my_secure_str = '' + + for i in range(ord(os.urandom(1))): + my_secure_str += ' Secure' + safestring.mark_safe(my_secure_str) + while ord(os.urandom(1)) % 2 == 0: + my_secure_str += ' Secure' + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_all_secure_case(self): + fdata = textwrap.dedent( + """ + import os + from django.utils import safestring + def all_secure_case(): + if ord(os.urandom(1)) % 2 == 0: + my_secure_str = 'Secure' + elif ord(os.urandom(1)) % 2 == 0: + my_secure_str = 'Secure' + else: + my_secure_str = 'Secure' + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_django_utils_mark_safe_my_insecure_str(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def insecure_function(text, cls=''): + return '

{text}

'.format( + text=text, cls=cls + ) + my_insecure_str = insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.mark_safe(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(10, issue.lineno) + self.assertEqual([10], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_utils_safetext_my_insecure_str(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def insecure_function(text, cls=''): + return '

{text}

'.format( + text=text, cls=cls + ) + my_insecure_str = insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.SafeText(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(10, issue.lineno) + self.assertEqual([10], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_utils_safeunicode_my_insecure_str(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def insecure_function(text, cls=''): + return '

{text}

'.format( + text=text, cls=cls + ) + my_insecure_str = insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.SafeUnicode(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(10, issue.lineno) + self.assertEqual([10], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_utils_safestring_my_insecure_str(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def insecure_function(text, cls=''): + return '

{text}

'.format( + text=text, cls=cls + ) + my_insecure_str = insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.SafeString(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(10, issue.lineno) + self.assertEqual([10], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_utils_safebytes_my_insecure_str(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def insecure_function(text, cls=''): + return '

{text}

'.format( + text=text, cls=cls + ) + my_insecure_str = insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.SafeBytes(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(10, issue.lineno) + self.assertEqual([10], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_django_utils_mark_safe_try_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def try_insecure(cls='" onload="alert("xss")'): + try: + my_insecure_str = insecure_function('insecure', cls=cls) + except Exception: + my_insecure_str = 'Secure' + safestring.mark_safe(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(8, issue.lineno) + self.assertEqual([8], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_except_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def except_insecure(cls='" onload="alert("xss")'): + try: + my_insecure_str = 'Secure' + except Exception: + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(8, issue.lineno) + self.assertEqual([8], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_try_else_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def try_else_insecure(cls='" onload="alert("xss")'): + try: + if 1 == random.randint(0, 1): # nosec + raise Exception + except Exception: + my_insecure_str = 'Secure' + else: + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(11, issue.lineno) + self.assertEqual([11], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_finally_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def finally_insecure(cls='" onload="alert("xss")'): + try: + if 1 == random.randint(0, 1): # nosec + raise Exception + except Exception: + print("Exception") + else: + print("No Exception") + finally: + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe(my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(13, issue.lineno) + self.assertEqual([13], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_format_arg_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def format_arg_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('{} {}'.format( + my_insecure_str, 'STR') + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([5, 6, 7], issue.linerange) + else: + self.assertEqual([5, 6], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_format_startarg_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def format_startarg_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('{}'.format(*[my_insecure_str])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_format_keywords_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def format_keywords_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('{b}'.format(b=my_insecure_str)) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_format_kwargs_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def format_kwargs_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('{b}'.format( + **{'b': my_insecure_str}) + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([5, 6, 7], issue.linerange) + else: + self.assertEqual([5, 6], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_percent_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def percent_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('%s' % my_insecure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_percent_list_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def percent_list_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('%s %s' % (my_insecure_str, 'b')) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_percent_dict_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def percent_dict_insecure(cls='" onload="alert("xss")'): + my_insecure_str = insecure_function('insecure', cls=cls) + safestring.mark_safe('%(b)s' % {'b': my_insecure_str}) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_import_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def import_insecure(): + import sre_constants + safestring.mark_safe(sre_constants.ANY) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_import_as_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def import_as_insecure(): + import sre_constants.ANY as any_str + safestring.mark_safe(any_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_from_import_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def from_import_insecure(): + from sre_constants import ANY + safestring.mark_safe(ANY) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_from_import_as_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def from_import_as_insecure(): + from sre_constants import ANY as any_str + safestring.mark_safe(any_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_with_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def with_insecure(path): + with open(path) as f: + safestring.mark_safe(f.read()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_django_utils_mark_safe_also_with_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def also_with_insecure(path): + with open(path) as f: + safestring.mark_safe(f) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_django_utils_mark_safe_for_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def for_insecure(): + my_secure_str = '' + for i in range(random.randint(0, 1)): # nosec + my_secure_str += insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(9, issue.lineno) + self.assertEqual([9], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_while_insecure(self): + fdata = textwrap.dedent( + """ + import os + from django.utils import safestring + def while_insecure(): + my_secure_str = '' + while ord(os.urandom(1)) % 2 == 0: + my_secure_str += insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(10, issue.lineno) + self.assertEqual([10], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_some_insecure_case(self): + fdata = textwrap.dedent( + """ + import os + from django.utils import safestring + def some_insecure_case(): + if ord(os.urandom(1)) % 2 == 0: + my_secure_str = insecure_function( + 'insecure', cls='" onload="alert("xss")' + ) + elif ord(os.urandom(1)) % 2 == 0: + my_secure_str = 'Secure' + else: + my_secure_str = 'Secure' + safestring.mark_safe(my_secure_str) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(13, issue.lineno) + self.assertEqual([13], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_test_insecure_shadow(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + mystr = 'insecure' + def test_insecure_shadow(): # var assigned out of scope + safestring.mark_safe(mystr) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(5, issue.lineno) + self.assertEqual([5], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_test_insecure(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def test_insecure(str_arg): + safestring.mark_safe(str_arg) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_test_insecure_with_assign(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def test_insecure_with_assign(str_arg=None): + if not str_arg: + str_arg = 'could be insecure' + safestring.mark_safe(str_arg) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(6, issue.lineno) + self.assertEqual([6], issue.linerange) + self.assertEqual(4, issue.col_offset) + + def test_django_utils_mark_safe_test_insecure_tuple_assign(self): + fdata = textwrap.dedent( + """ + from django.utils import safestring + def test_insecure_tuple_assign(): + HTML_CHOICES = ( + (_('Donate'), 'https://example.org/donate/'), + (_('More info'), 'https://example.org/'), + ) + text, url = choice(HTML_CHOICES) + safestring.mark_safe('{1}'.format(url, text)) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B703", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(9, issue.lineno) + self.assertEqual([9], issue.linerange) + self.assertEqual(4, issue.col_offset) diff --git a/tests/unit/plugins/test_exec.py b/tests/unit/plugins/test_exec.py new file mode 100644 index 00000000..db71bbe3 --- /dev/null +++ b/tests/unit/plugins/test_exec.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class ExecTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B102"]) + + def test_exec_used(self): + fdata = "exec('do evil')" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_general_bad_file_permissions.py b/tests/unit/plugins/test_general_bad_file_permissions.py new file mode 100644 index 00000000..0bd2b4dd --- /dev/null +++ b/tests/unit/plugins/test_general_bad_file_permissions.py @@ -0,0 +1,212 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class GeneralBadFilePermissionsTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B103"]) + + def test_chmod_octal_227(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o227) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_octal_7(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o7) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_octal_664(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o664) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_octal_777(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o777) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_octal_770(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o770) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_octal_776(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o776) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_octal_760(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', 0o760) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_decimal_511(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('~/.bashrc', 511) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_hex_1ff(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/tmp/oh_hai', 0x1ff) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_chmod_stat_s_irwxu(self): + fdata = textwrap.dedent( + """ + import os + os.chmod('/etc/passwd', stat.S_IRWXU) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_chmod_file_as_arg(self): + fdata = textwrap.dedent( + """ + import os + key_file = 'foo' + os.chmod(key_file, 0o777) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INCORRECT_PERMISSION_ASSIGNMENT, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_general_bind_all_interfaces.py b/tests/unit/plugins/test_general_bind_all_interfaces.py new file mode 100644 index 00000000..91412b16 --- /dev/null +++ b/tests/unit/plugins/test_general_bind_all_interfaces.py @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class GeneralBindAllInterfacesTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B104"]) + + def test_bind_all_interfaces(self): + fdata = textwrap.dedent( + """ + import socket + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('0.0.0.0', 31137)) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.MULTIPLE_BINDS, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_bind_address(self): + fdata = textwrap.dedent( + """ + import socket + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('192.168.0.1', 8080)) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_general_hardcoded_password.py b/tests/unit/plugins/test_general_hardcoded_password.py new file mode 100644 index 00000000..1acf1ca2 --- /dev/null +++ b/tests/unit/plugins/test_general_hardcoded_password.py @@ -0,0 +1,250 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class GeneralHardcodedPasswordTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B105", "B106", "B107"]) + + def test_class_attribute(self): + fdata = textwrap.dedent( + """ + class SomeClass: + password = "class_password" + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(15, issue.col_offset) + + def test_function_kwarg(self): + fdata = textwrap.dedent( + """ + def someFunction(user, password="Admin"): + print("Hi " + user) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B107", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(2, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([2, 3], issue.linerange) + else: + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_function_password_eq_root(self): + fdata = textwrap.dedent( + """ + def someFunction2(password): + if password == "root": + print("OK, logged in") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(19, issue.col_offset) + + def test_function_password_eq_empty(self): + fdata = textwrap.dedent( + """ + def noMatch(password): + if password == '': + print("No password!") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(19, issue.col_offset) + + def test_function_password_eq_ajklawejrkl42348swfgkg(self): + fdata = textwrap.dedent( + """ + def NoMatch2(password): + if password == "ajklawejrkl42348swfgkg": + print("Nice password!") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(19, issue.col_offset) + + def test_function_obj_password_eq(self): + fdata = textwrap.dedent( + """ + def noMatchObject(): + obj = SomeClass() + if obj.password == "this cool password": + print(obj.password) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(23, issue.col_offset) + + def test_function_kwarg2(self): + fdata = textwrap.dedent( + """ + def doLogin(password="blerg"): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B107", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(2, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([2, 3], issue.linerange) + else: + self.assertEqual([2], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_function_no_password(self): + fdata = textwrap.dedent( + """ + def NoMatch3(a, b): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_call_kwarg(self): + fdata = 'doLogin(password="blerg")' + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B106", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_password_blerg(self): + fdata = 'password = "blerg"' + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(11, issue.col_offset) + + def test_dict_password_blerg(self): + fdata = 'd["password"] = "blerg"' + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(2, issue.col_offset) + + def test_email_password_secret(self): + fdata = 'EMAIL_PASSWORD = "secret"' + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(17, issue.col_offset) + + def test_email_pwd_emails_secret(self): + fdata = "email_pwd = 'emails_secret'" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_my_secret_password_for_email(self): + fdata = "my_secret_password_for_email = 'd6s$f9g!j8mg7hw?n&2'" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(31, issue.col_offset) + + def test_passphrase_1234(self): + fdata = "passphrase='1234'" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B105", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.HARD_CODED_PASSWORD, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(11, issue.col_offset) diff --git a/tests/unit/plugins/test_general_hardcoded_tmp.py b/tests/unit/plugins/test_general_hardcoded_tmp.py new file mode 100644 index 00000000..439ae506 --- /dev/null +++ b/tests/unit/plugins/test_general_hardcoded_tmp.py @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class GeneralHardcodedTmpTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B108"]) + + def test_tmp(self): + fdata = textwrap.dedent( + """ + with open('/tmp/abc', 'w') as f: + f.write('def') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.INSECURE_TEMP_FILE, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(10, issue.col_offset) + + def test_var_tmp(self): + fdata = textwrap.dedent( + """ + with open('/var/tmp/123', 'w') as f: + f.write('def') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.INSECURE_TEMP_FILE, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(10, issue.col_offset) + + def test_dev_shm(self): + fdata = textwrap.dedent( + """ + with open('/dev/shm/unit/test', 'w') as f: + f.write('def') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.INSECURE_TEMP_FILE, issue.cwe.id) + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + self.assertEqual(10, issue.col_offset) + + def test_abc_tmp(self): + fdata = textwrap.dedent( + """ + with open('/abc/tmp', 'w') as f: + f.write('def') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_foo_bar(self): + fdata = textwrap.dedent( + """ + with open('/foo/bar', 'w') as f: + f.write('def') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_hashlib_insecure_functions.py b/tests/unit/plugins/test_hashlib_insecure_functions.py new file mode 100644 index 00000000..7803437c --- /dev/null +++ b/tests/unit/plugins/test_hashlib_insecure_functions.py @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class HashlibInsecureFunctionsTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B324"]) + + def test_hashlib_new_md4(self): + fdata = "hashlib.new('md4')" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + if sys.version_info >= (3, 9): + self.assertEqual(bandit.HIGH, issue.severity) + else: + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_new_md5(self): + fdata = "hashlib.new('md5')" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + if sys.version_info >= (3, 9): + self.assertEqual(bandit.HIGH, issue.severity) + else: + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_new_sha(self): + fdata = "hashlib.new('sha')" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + if sys.version_info >= (3, 9): + self.assertEqual(bandit.HIGH, issue.severity) + else: + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_new_sha1(self): + fdata = "hashlib.new('sha1')" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + if sys.version_info >= (3, 9): + self.assertEqual(bandit.HIGH, issue.severity) + else: + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_new_name_md5(self): + fdata = "hashlib.new(name='md5', data=b'test')" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + if sys.version_info >= (3, 9): + self.assertEqual(bandit.HIGH, issue.severity) + else: + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_new_sha256(self): + fdata = "hashlib.new(name='sha256')" + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_hashlib_new_sha512(self): + fdata = "hashlib.new('SHA512')" + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_hashlib_new_usedforsecurity_true(self): + fdata = "hashlib.new('sha1', usedforsecurity=True)" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + if sys.version_info >= (3, 9): + self.assertEqual(bandit.HIGH, issue.severity) + else: + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_new_usedforsecurity_false(self): + fdata = "hashlib.new(name='sha1', usedforsecurity=False)" + self.visitor.process(fdata) + if sys.version_info >= (3, 9): + self.assertEqual(0, len(self.visitor.tester.results)) + else: + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_md4(self): + if sys.version_info >= (3, 9): + fdata = "hashlib.md4()" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_md5(self): + if sys.version_info >= (3, 9): + fdata = "hashlib.md5()" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_sha(self): + if sys.version_info >= (3, 9): + fdata = "hashlib.sha()" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_sha1(self): + if sys.version_info >= (3, 9): + fdata = "hashlib.sha1()" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_hashlib_sha256(self): + fdata = "hashlib.sha256()" + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_hashlib_usedforsecurity_false(self): + if sys.version_info >= (3, 9): + fdata = "hashlib.md5(usedforsecurity=False)" + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_hashlib_usedforsecurity_true(self): + if sys.version_info >= (3, 9): + fdata = "hashlib.sha1(usedforsecurity=True)" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_injection_paramiko.py b/tests/unit/plugins/test_injection_paramiko.py new file mode 100644 index 00000000..6e0cb1e7 --- /dev/null +++ b/tests/unit/plugins/test_injection_paramiko.py @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class InjectionParamikoTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B601"]) + + def test_exec_command(self): + fdata = textwrap.dedent( + """ + import paramiko + client = paramiko.client.SSHClient() + client.exec_command('something; really; unsafe') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_exec_command_no_import(self): + fdata = textwrap.dedent( + """ + client = Client() + client.exec_command('test') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_injection_shell.py b/tests/unit/plugins/test_injection_shell.py new file mode 100644 index 00000000..108a19ea --- /dev/null +++ b/tests/unit/plugins/test_injection_shell.py @@ -0,0 +1,1393 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class InjectionShellTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B602", "B603", "B604", "B605", "B606", "B607"]) + + def test_popen_shell_true(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen + Popen('/bin/gcc --version', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_shell_true(self): + fdata = textwrap.dedent( + """ + def Popen(*args, **kwargs): + print('hi') + + def __len__(self): + return 0 + Popen('/bin/gcc --version', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B604", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_arg_list_shell_false(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen(['/bin/gcc', '--version'], shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_arg_list(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen(['/bin/gcc', '--version']) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_arg_list_multiline(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.call(["/bin/ls", + "-l" + ]) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4, 5], issue.linerange) + else: + self.assertEqual([3, 4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.call('/bin/ls -l', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_check_call_arg_list_shell_false(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.check_call(['/bin/ls', '-l'], shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_check_call_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.check_call('/bin/ls -l', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_check_output_arg_list(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.check_output(['/bin/ls', '-l']) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_check_output_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.check_output('/bin/ls -l', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_run_shell_arg_list(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.run(['/bin/ls', '-l']) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_run_shell_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.run('/bin/ls -l', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_wildcard_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen('/bin/ls *', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_string_sub_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen('/bin/ls %s' % ('something',), shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_string_format_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen('/bin/ls {}'.format('something'), shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_command_as_var_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + command = "/bin/ls" + unknown_function() + subprocess.Popen(command, shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_and_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen('/bin/ls && cat /etc/passwd', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell='True') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_false_str(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell='False') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_none_str(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell='None') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_1(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_popen(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=Popen()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_true_list(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=[True]) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_dict(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell={'IS': 'True'}) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_var(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=command) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B602", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_false(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_0(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=0) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_empty_list(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=[]) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_empty_dict(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell={}) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_call_command_as_var_shell_none(self): + fdata = textwrap.dedent( + """ + import subprocess + command = 'pwd' + subprocess.call(command, shell=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_system(self): + fdata = textwrap.dedent( + """ + import os + os.system('/bin/echo hi') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execl(self): + fdata = textwrap.dedent( + """ + import os + os.execl(path, arg0, arg1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execle(self): + fdata = textwrap.dedent( + """ + import os + os.execle(path, arg0, arg1, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execlp(self): + fdata = textwrap.dedent( + """ + import os + os.execlp(file, arg0, arg1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execlpe(self): + fdata = textwrap.dedent( + """ + import os + os.execlpe(file, arg0, arg1, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execv(self): + fdata = textwrap.dedent( + """ + import os + os.execv(path, args) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execve(self): + fdata = textwrap.dedent( + """ + import os + os.execve(path, args, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execvp(self): + fdata = textwrap.dedent( + """ + import os + os.execvp(file, args) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_execvpe(self): + fdata = textwrap.dedent( + """ + import os + os.execvpe(file, args, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnl(self): + fdata = textwrap.dedent( + """ + import os + os.spawnl(mode, path) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnle(self): + fdata = textwrap.dedent( + """ + import os + os.spawnle(mode, path, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnlp(self): + fdata = textwrap.dedent( + """ + import os + os.spawnlp(mode, file) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnlpe(self): + fdata = textwrap.dedent( + """ + import os + os.spawnlpe(mode, file, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnv(self): + fdata = textwrap.dedent( + """ + import os + os.spawnv(mode, path, args) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnve(self): + fdata = textwrap.dedent( + """ + import os + os.spawnve(mode, path, args, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnvp(self): + fdata = textwrap.dedent( + """ + import os + os.spawnvp(mode, file, args) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_spawnvpe(self): + fdata = textwrap.dedent( + """ + import os + os.spawnvpe(mode, file, args, env) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_startfile_foo(self): + fdata = textwrap.dedent( + """ + import os + os.startfile('/bin/foo.docx') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_startfile_bad(self): + fdata = textwrap.dedent( + """ + import os + os.startfile('/bin/bad.exe') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_startfile_text(self): + fdata = textwrap.dedent( + """ + import os + os.startfile('/bin/text.txt') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B606", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_popen_uname(self): + fdata = textwrap.dedent( + """ + import os + os.popen('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_popen_uname(self): + fdata = textwrap.dedent( + """ + from os import popen + popen('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_o_popen_uname(self): + fdata = textwrap.dedent( + """ + import os as o + o.popen('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pos_uname(self): + fdata = textwrap.dedent( + """ + from os import popen as pos + pos('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_popen2_uname(self): + fdata = textwrap.dedent( + """ + import os + os.popen2('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_popen3_uname(self): + fdata = textwrap.dedent( + """ + import os + os.popen3('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_popen4_uname(self): + fdata = textwrap.dedent( + """ + import os + os.popen4('/bin/uname -av') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_popen4_uname_rm(self): + fdata = textwrap.dedent( + """ + import os + os.popen4('/bin/uname -av; rm -rf /') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_popen4_some_var(self): + fdata = textwrap.dedent( + """ + import os + os.popen4(some_var) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pop_gcc_partial_path(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop('gcc --version', shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(2, len(self.visitor.tester.results)) + issue1 = self.visitor.tester.results[0] + self.assertEqual("B607", issue1.test_id) + self.assertEqual(bandit.LOW, issue1.severity) + self.assertEqual(bandit.HIGH, issue1.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue1.cwe.id) + self.assertEqual(3, issue1.lineno) + self.assertEqual([3], issue1.linerange) + self.assertEqual(0, issue1.col_offset) + issue2 = self.visitor.tester.results[1] + self.assertEqual("B603", issue2.test_id) + self.assertEqual(bandit.LOW, issue2.severity) + self.assertEqual(bandit.HIGH, issue2.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue2.cwe.id) + self.assertEqual(3, issue2.lineno) + self.assertEqual([3], issue2.linerange) + self.assertEqual(0, issue2.col_offset) + + def test_pop_gcc_absolute_path(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop('/bin/gcc --version', shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pop_var_shell_false(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop(var, shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pop_partial_path_arg_list_shell_false(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop(['ls', '-l'], shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(2, len(self.visitor.tester.results)) + issue1 = self.visitor.tester.results[0] + self.assertEqual("B607", issue1.test_id) + self.assertEqual(bandit.LOW, issue1.severity) + self.assertEqual(bandit.HIGH, issue1.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue1.cwe.id) + self.assertEqual(3, issue1.lineno) + self.assertEqual([3], issue1.linerange) + self.assertEqual(0, issue1.col_offset) + issue2 = self.visitor.tester.results[1] + self.assertEqual("B603", issue2.test_id) + self.assertEqual(bandit.LOW, issue2.severity) + self.assertEqual(bandit.HIGH, issue2.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue2.cwe.id) + self.assertEqual(3, issue2.lineno) + self.assertEqual([3], issue2.linerange) + self.assertEqual(0, issue2.col_offset) + + def test_pop_absolute_path_arg_list_shell_false(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop(['/bin/ls', '-l'], shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pop_ls_shell_false(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop('../ls -l', shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pop_windows_path_shell_false(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop('c:\\hello\\something', shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pop_linux_path_shell_false(self): + fdata = textwrap.dedent( + """ + from subprocess import Popen as pop + pop('c:/hello/something_else', shell=False) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B603", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_commands_getstatusoutput(self): + fdata = textwrap.dedent( + """ + import commands + print(commands.getstatusoutput('/bin/echo / | xargs ls')) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) + + def test_commands_getoutput(self): + fdata = textwrap.dedent( + """ + import commands + print(commands.getoutput('/bin/echo / | xargs ls')) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) + + def test_commands_getstatus(self): + fdata = textwrap.dedent( + """ + import commands + print(commands.getstatus('/bin/echo / | xargs ls')) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_popen2_popen2(self): + fdata = textwrap.dedent( + """ + import popen2 + print(popen2.popen2('/bin/echo / | xargs ls')[0].read()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) + + def test_popen2_popen3(self): + fdata = textwrap.dedent( + """ + import popen2 + print(popen2.popen3('/bin/echo / | xargs ls')[0].read()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) + + def test_popen2_popen4(self): + fdata = textwrap.dedent( + """ + import popen2 + print(popen2.popen4('/bin/echo / | xargs ls')[0].read()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) + + def test_popen2_popen3_fromchild_read(self): + fdata = textwrap.dedent( + """ + import popen2 + print(popen2.Popen3('/bin/echo / | xargs ls').fromchild.read()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) + + def test_popen2_popen4_fromchild_read(self): + fdata = textwrap.dedent( + """ + import popen2 + print(popen2.Popen3('/bin/echo / | xargs ls').fromchild.read()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B605", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.OS_COMMAND_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(6, issue.col_offset) diff --git a/tests/unit/plugins/test_injection_sql.py b/tests/unit/plugins/test_injection_sql.py new file mode 100644 index 00000000..30f8f0e6 --- /dev/null +++ b/tests/unit/plugins/test_injection_sql.py @@ -0,0 +1,238 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class InsecureSqlTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B608"]) + + def test_query_select_from_where(self): + fdata = """query = "SELECT * FROM foo WHERE id = '%s'" % identifier""" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_query_insert_into_values(self): + fdata = """query = "INSERT INTO foo VALUES ('a', 'b', '%s')" % value""" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_query_delete_from_where(self): + fdata = """query = "DELETE FROM foo WHERE id = '%s'" % identifier""" + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_query_update_set_where(self): + fdata = ( + """query = "UPDATE foo SET value = 'b' WHERE id = """ + """'%s'" % identifier""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_query_with_as_select_from_select_from_where(self): + fdata = '''query = """WITH cte AS (SELECT x FROM foo) + SELECT x FROM cte WHERE x = '%s'""" % identifier + ''' + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + if sys.version_info >= (3, 8): + self.assertEqual(1, issue.lineno) + self.assertEqual([1, 2], issue.linerange) + self.assertEqual(8, issue.col_offset) + else: + self.assertEqual(2, issue.lineno) + self.assertEqual([2], issue.linerange) + # FIXME: col_offset should never be negative + self.assertEqual(-1, issue.col_offset) + + def test_query_select_from_where_identifier(self): + fdata = """query = "SELECT * FROM foo WHERE id = '" + identifier + "'" + """ + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_query_select_from_where_format_identifier(self): + fdata = ( + """query = "SELECT * FROM foo WHERE id = """ + """'{}'".format(identifier)""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(8, issue.col_offset) + + def test_execute_select_from_where_identifier(self): + fdata = ( + """cur.execute("SELECT * FROM foo WHERE id = '%s'" """ + """% identifier)""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_execute_insert_values(self): + fdata = ( + """cur.execute("INSERT INTO foo VALUES ('a', 'b', '%s')" """ + """% value)""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_execute_delete_from_where_identifier(self): + fdata = """cur.execute("DELETE FROM foo WHERE id = '%s'" % identifier) + """ + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_execute_update_set_where_identifier(self): + fdata = ( + """cur.execute("UPDATE foo SET value = 'b' WHERE id = """ + """'%s'" % identifier)""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_execute_select_from_where_identifier_2(self): + fdata = ( + """cur.execute("SELECT * FROM foo WHERE id = """ + """'" + identifier + "'")""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_execute_select_from_where_identifier_format(self): + fdata = ( + """cur.execute("SELECT * FROM foo WHERE id = """ + """'{}'".format(identifier))""" + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.SQL_INJECTION, issue.cwe.id) + self.assertEqual(1, issue.lineno) + self.assertEqual([1], issue.linerange) + self.assertEqual(12, issue.col_offset) + + def test_execute_select_from_where_identifier_good(self): + fdata = """cur.execute("SELECT * FROM foo WHERE id = '%s'", identifier) + """ + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_execute_insert_into_values_good(self): + fdata = ( + """cur.execute("INSERT INTO foo VALUES ('a', 'b', '%s')", """ + """value)""" + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_execute_delete_from_where_good(self): + fdata = """cur.execute("DELETE FROM foo WHERE id = '%s'", identifier) + """ + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_execute_update_set_where_good(self): + fdata = ( + """cur.execute("UPDATE foo SET value = 'b' WHERE id = """ + """'%s'", identifier)""" + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_non_sql_select_statement(self): + fdata = """choices=[('server_list', _("Select from active instances"))] + """ + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_non_sql_delete_statement(self): + fdata = """print("delete from the cache as the first argument") + """ + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_injection_wildcard.py b/tests/unit/plugins/test_injection_wildcard.py new file mode 100644 index 00000000..c62b16c1 --- /dev/null +++ b/tests/unit/plugins/test_injection_wildcard.py @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class InjectionWildcardTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B609"]) + + def test_os_system_tar(self): + fdata = textwrap.dedent( + """ + import os + os.system("/bin/tar xvzf *") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_WILDCARD_NEUTRALIZATION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_system_chown(self): + fdata = textwrap.dedent( + """ + import os + os.system('/bin/chown *') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_WILDCARD_NEUTRALIZATION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_os_system_chmod(self): + fdata = textwrap.dedent( + """ + import os + os.popen2('/bin/chmod *') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_WILDCARD_NEUTRALIZATION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_chown_shell_true(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen('/bin/chown *', shell=True) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_WILDCARD_NEUTRALIZATION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_subprocess_popen_rsync(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen('/bin/rsync *') + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_subprocess_popen_chmod(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen("/bin/chmod *") + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_subprocess_popen_chown(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen(['/bin/chown', '*']) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_subprocess_popen_chmod_argv(self): + fdata = textwrap.dedent( + """ + import subprocess + subprocess.Popen(["/bin/chmod", sys.argv[1], "*"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_os_spawnvp(self): + fdata = textwrap.dedent( + """ + import os + os.spawnvp(os.P_WAIT, 'tar', ['tar', 'xvzf', '*']) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_insecure_ssl_tls.py b/tests/unit/plugins/test_insecure_ssl_tls.py new file mode 100644 index 00000000..8d1313f8 --- /dev/null +++ b/tests/unit/plugins/test_insecure_ssl_tls.py @@ -0,0 +1,453 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class InsecureSslTlsTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B502", "B503", "B504"]) + + def test_ssl_wrap_socket_ssl_v2(self): + fdata = textwrap.dedent( + """ + import ssl + ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_ssl_wrap_socket_ssl_v3(self): + fdata = textwrap.dedent( + """ + import ssl + ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_ssl_wrap_socket_tls_v1(self): + fdata = textwrap.dedent( + """ + import ssl + ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_ssl_wrap_socket_tls_v11(self): + fdata = textwrap.dedent( + """ + import ssl + ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_ssl_wrap_socket(self): + fdata = textwrap.dedent( + """ + import ssl + ssl.wrap_socket() + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B504", issue.test_id) + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_protocol_ssl_v2(self): + fdata = textwrap.dedent( + """ + import ssl + herp_derp(ssl_version=ssl.PROTOCOL_SSLv2) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_protocol_ssl_v3(self): + fdata = textwrap.dedent( + """ + import ssl + herp_derp(ssl_version=ssl.PROTOCOL_SSLv3) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_protocol_tls_v1(self): + fdata = textwrap.dedent( + """ + import ssl + herp_derp(ssl_version=ssl.PROTOCOL_TLSv1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_protocol_tls_v11(self): + fdata = textwrap.dedent( + """ + import ssl + herp_derp(ssl_version=ssl.PROTOCOL_TLSv1_1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_func_protocol_ssl_v2(self): + fdata = textwrap.dedent( + """ + import ssl + def open_ssl_socket(version=ssl.PROTOCOL_SSLv2): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B503", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4], issue.linerange) + else: + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pyopenssl_ssl_v2(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + SSL.Context(method=SSL.SSLv2_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pyopenssl_ssl_v23(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + SSL.Context(method=SSL.SSLv23_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pyopenssl_ssl_v3(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + SSL.Context(method=SSL.SSLv3_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pyopenssl_tls_v1(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + SSL.Context(method=SSL.TLSv1_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pyopenssl_tls_v11(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + SSL.Context(method=SSL.TLSv1_1_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_pyopenssl_ssl_v2(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + herp_derp(method=SSL.SSLv2_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_pyopenssl_ssl_v23(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + herp_derp(method=SSL.SSLv23_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_pyopenssl_ssl_v3(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + herp_derp(method=SSL.SSLv3_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_pyopenssl_tls_v1(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + herp_derp(method=SSL.TLSv1_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_call_pyopenssl_tls_v11(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + herp_derp(method=SSL.TLSv1_1_METHOD) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B502", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_func_pyopenssl_ssl_v2(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + def open_ssl_socket(version=SSL.SSLv2_METHOD): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B503", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4], issue.linerange) + else: + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_func_pyopenssl_ssl_v23(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + def open_ssl_socket(version=SSL.SSLv23_METHOD): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B503", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4], issue.linerange) + else: + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_func_pyopenssl_tls_v11(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + def open_ssl_socket(version=SSL.TLSv1_1_METHOD): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B503", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.BROKEN_CRYPTO, issue.cwe.id) + self.assertEqual(3, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([3, 4], issue.linerange) + else: + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_func_pyopenssl_tls_v12(self): + fdata = textwrap.dedent( + """ + from pyOpenSSL import SSL + def open_ssl_socket(version=SSL.TLSv1_2_METHOD): + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_jinja2_templates.py b/tests/unit/plugins/test_jinja2_templates.py new file mode 100644 index 00000000..b748937e --- /dev/null +++ b/tests/unit/plugins/test_jinja2_templates.py @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class Jinja2TemplatesTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B701"]) + + def test_environment_autoescape_false(self): + fdata = textwrap.dedent( + """ + import jinja2 + templateLoader = jinja2.FileSystemLoader(searchpath="/") + jinja2.Environment(autoescape=False, loader=templateLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CODE_INJECTION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_environment_autoescape_true(self): + fdata = textwrap.dedent( + """ + import jinja2 + templateLoader = jinja2.FileSystemLoader(searchpath="/") + jinja2.Environment(autoescape=True, loader=templateLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_environment_autoescape_select(self): + fdata = textwrap.dedent( + """ + import jinja2 + from jinja2 import Environment + from jinja2 import select_autoescape + templateLoader = jinja2.FileSystemLoader(searchpath="/") + Environment(loader=templateLoader, autoescape=select_autoescape()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_environment_autoescape_jinja2_select(self): + fdata = textwrap.dedent( + """ + import jinja2 + from jinja2 import Environment + templateLoader = jinja2.FileSystemLoader(searchpath="/") + Environment(loader=templateLoader, + autoescape=jinja2.select_autoescape(['html', 'htm', 'xml'])) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_environment_autoescape_func(self): + fdata = textwrap.dedent( + """ + import jinja2 + from jinja2 import Environment + templateLoader = jinja2.FileSystemLoader(searchpath="/") + def fake_func(): + return 'foobar' + Environment(loader=templateLoader, autoescape=fake_func()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.CODE_INJECTION, issue.cwe.id) + self.assertEqual(7, issue.lineno) + self.assertEqual([7], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_logging_config_insecure_listen.py b/tests/unit/plugins/test_logging_config_insecure_listen.py new file mode 100644 index 00000000..8fc8d347 --- /dev/null +++ b/tests/unit/plugins/test_logging_config_insecure_listen.py @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class LoggingConfigListenTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B612"]) + + def test_logging_config_listen(self): + fdata = textwrap.dedent( + """ + from logging import config + server = config.listen(9999) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CODE_INJECTION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(9, issue.col_offset) + + def test_logging_config_listen_verify(self): + fdata = textwrap.dedent( + """ + from logging import config + server = config.listen(9999, verify=lambda x: x) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_mako_templates.py b/tests/unit/plugins/test_mako_templates.py new file mode 100644 index 00000000..46316a22 --- /dev/null +++ b/tests/unit/plugins/test_mako_templates.py @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class MakoTemplatesTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B702"]) + + def test_template_template(self): + fdata = textwrap.dedent( + """ + from mako import template + template.Template("hello") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_mako_template_template(self): + fdata = textwrap.dedent( + """ + import mako + mako.template.Template("hello") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_template(self): + fdata = textwrap.dedent( + """ + from mako.template import Template + Template("hello") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.BASIC_XSS, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_request_without_timeout.py b/tests/unit/plugins/test_request_without_timeout.py new file mode 100644 index 00000000..acbaf7f5 --- /dev/null +++ b/tests/unit/plugins/test_request_without_timeout.py @@ -0,0 +1,347 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class RequestWithoutTimeoutTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B113"]) + + def test_requests_get_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.get('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_get_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.get('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_get_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.get('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_post_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.post('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_post_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.post('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_post_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.post('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_put_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.put('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_put_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.put('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_put_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.put('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_delete_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.delete('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_delete_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.delete('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_delete_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.delete('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_patch_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.patch('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_patch_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.patch('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_patch_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.patch('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_options_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.options('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_options_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.options('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_options_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.options('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_requests_head_default(self): + fdata = textwrap.dedent( + """ + import requests + requests.head('https://example.com') + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_head_with_timeout_none(self): + fdata = textwrap.dedent( + """ + import requests + requests.head('https://example.com', timeout=None) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.LOW, issue.confidence) + self.assertEqual( + b_issue.Cwe.UNCONTROLLED_RESOURCE_CONSUMPTION, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_requests_head_with_timeout(self): + fdata = textwrap.dedent( + """ + import requests + requests.head('https://example.com', timeout=5) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_snmp_security_check.py b/tests/unit/plugins/test_snmp_security_check.py new file mode 100644 index 00000000..829f182e --- /dev/null +++ b/tests/unit/plugins/test_snmp_security_check.py @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class SnmpSecurityCheckTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B508", "B509"]) + + def test_communitydata_mpmodel_zero(self): + fdata = textwrap.dedent( + """ + from pysnmp import hlapi + hlapi.CommunityData('public', mpModel=0) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B508", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_communitydata_mpmodel_one(self): + fdata = textwrap.dedent( + """ + from pysnmp import hlapi + hlapi.CommunityData('public', mpModel=1) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B508", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_usmuserdata_noauth_nopriv(self): + fdata = textwrap.dedent( + """ + from pysnmp import hlapi + hlapi.UsmUserData("securityName") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B509", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_usmuserdata_auth_nopriv(self): + fdata = textwrap.dedent( + """ + from pysnmp import hlapi + hlapi.UsmUserData("securityName", "authName") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual("B509", issue.test_id) + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.CLEARTEXT_TRANSMISSION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_usmuserdata_auth_priv(self): + fdata = textwrap.dedent( + """ + from pysnmp import hlapi + hlapi.UsmUserData("securityName", "authName", "privName") + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_ssh_no_host_key_verification.py b/tests/unit/plugins/test_ssh_no_host_key_verification.py new file mode 100644 index 00000000..86a7b3eb --- /dev/null +++ b/tests/unit/plugins/test_ssh_no_host_key_verification.py @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class SshNoHostKeyVerificationTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B507"]) + + def test_reject_policy(self): + fdata = textwrap.dedent( + """ + from paramiko import client + ssh_client = client.SSHClient() + ssh_client.set_missing_host_key_policy(client.RejectPolicy) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_auto_add_policy(self): + fdata = textwrap.dedent( + """ + from paramiko import client + ssh_client = client.SSHClient() + ssh_client.set_missing_host_key_policy(client.AutoAddPolicy) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_warning_policy(self): + fdata = textwrap.dedent( + """ + from paramiko import client + ssh_client = client.SSHClient() + ssh_client.set_missing_host_key_policy(client.WarningPolicy) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.MEDIUM, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_CERT_VALIDATION, issue.cwe.id) + self.assertEqual(4, issue.lineno) + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) diff --git a/tests/unit/plugins/test_try_except_continue.py b/tests/unit/plugins/test_try_except_continue.py new file mode 100644 index 00000000..7c80ff76 --- /dev/null +++ b/tests/unit/plugins/test_try_except_continue.py @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class TryExceptContinueTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B112"]) + + def test_try_except_continue(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except: + continue + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([4, 5], issue.linerange) + else: + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_except_exception_continue(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except Exception: + continue + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([4, 5], issue.linerange) + else: + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_multi_except_pass(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except ZeroDivisionError: + a = 2 + except Exception: + continue + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(6, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([6, 7], issue.linerange) + else: + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_except_continue_check_typed_exception_false(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except ZeroDivisionError: + continue + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_try_except_continue_check_typed_exception_true(self): + test = next( + x + for x in self.b_manager.b_ts.tests["ExceptHandler"] + if x.__name__ == "try_except_continue" + ) + test._config = {"check_typed_exception": True} + + fdata = textwrap.dedent( + """ + try: + a = 1 + except ZeroDivisionError: + continue + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([4, 5], issue.linerange) + else: + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_except_no_continue(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except: + a = 2 + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_try_except_silly(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except: + continue + a = 2 + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_try_except_pass.py b/tests/unit/plugins/test_try_except_pass.py new file mode 100644 index 00000000..548636d0 --- /dev/null +++ b/tests/unit/plugins/test_try_except_pass.py @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: Apache-2.0 +import sys +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class TryExceptPassTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B110"]) + + def test_try_except_pass(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except: + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([4, 5], issue.linerange) + else: + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_except_exception_pass(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except Exception: + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([4, 5], issue.linerange) + else: + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_multi_except_pass(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except ZeroDivisionError: + a = 2 + except Exception: + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(6, issue.lineno) + + if sys.version_info >= (3, 8): + self.assertEqual([6, 7], issue.linerange) + else: + self.assertEqual([6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_except_pass_check_typed_exception_false(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except ZeroDivisionError: + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_try_except_pass_check_typed_exception_true(self): + test = next( + x + for x in self.b_manager.b_ts.tests["ExceptHandler"] + if x.__name__ == "try_except_pass" + ) + test._config = {"check_typed_exception": True} + + fdata = textwrap.dedent( + """ + try: + a = 1 + except ZeroDivisionError: + pass + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.LOW, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.IMPROPER_CHECK_OF_EXCEPT_COND, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + if sys.version_info >= (3, 8): + self.assertEqual([4, 5], issue.linerange) + else: + self.assertEqual([4], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_try_except_no_pass(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except: + a = 2 + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_try_except_silly(self): + fdata = textwrap.dedent( + """ + try: + a = 1 + except: + pass + a = 2 + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_weak_cryptographic_key.py b/tests/unit/plugins/test_weak_cryptographic_key.py new file mode 100644 index 00000000..d9368297 --- /dev/null +++ b/tests/unit/plugins/test_weak_cryptographic_key.py @@ -0,0 +1,438 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class WeakCryptographicKeyTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B505"]) + + def test_cryptography_dsa_2048(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import dsa + dsa.generate_private_key(key_size=2048, + backend=backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cryptography_ec_secp384r1(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import ec + ec.generate_private_key(curve=ec.SECP384R1, + backend=backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cryptography_rsa_2048(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import rsa + rsa.generate_private_key(public_exponent=65537, + key_size=2048, + backend=backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycrypto_dsa_2048(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import DSA as pycrypto_dsa + pycrypto_dsa.generate(bits=2048) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycrypto_rsa_2048(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import RSA as pycrypto_rsa + pycrypto_rsa.generate(bits=2048) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycryptodomex_dsa_2048(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import DSA as pycryptodomex_dsa + pycryptodomex_dsa.generate(bits=2048) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycryptodomex_rsa_2048(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import RSA as pycryptodomex_rsa + pycryptodomex_rsa.generate(bits=2048) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cryptography_dsa_4096(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import dsa + dsa.generate_private_key(4096, + backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cryptography_ec_secp256k1(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import ec + ec.generate_private_key(ec.SECP256K1, + backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cryptography_rsa_4096(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import rsa + rsa.generate_private_key(3, + 4096, + backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycrypto_dsa_4096(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import DSA as pycrypto_dsa + pycrypto_dsa.generate(4096) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycrypto_rsa_4096(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import RSA as pycrypto_rsa + pycrypto_rsa.generate(4096) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycryptodomex_dsa_4096(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import DSA as pycryptodomex_dsa + pycryptodomex_dsa.generate(4096) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_pycryptodomex_rsa_4096(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import RSA as pycryptodomex_rsa + pycryptodomex_rsa.generate(4096) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_cryptography_dsa_1024(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import dsa + dsa.generate_private_key(key_size=1024, + backend=backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4, 5], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_ec_sect163r2(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import ec + ec.generate_private_key(curve=ec.SECT163R2, + backend=backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4, 5], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_rsa_1024(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import rsa + rsa.generate_private_key(public_exponent=65537, + key_size=1024, + backend=backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4, 5, 6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycrypto_dsa_1024(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import DSA as pycrypto_dsa + pycrypto_dsa.generate(bits=1024) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycrypto_rsa_1024(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import RSA as pycrypto_rsa + pycrypto_rsa.generate(bits=1024) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycryptodomex_dsa_1024(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import DSA as pycryptodomex_dsa + pycryptodomex_dsa.generate(bits=1024) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycryptodomex_rsa_1024(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import RSA as pycryptodomex_rsa + pycryptodomex_rsa.generate(bits=1024) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_dsa_512(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import dsa + dsa.generate_private_key(512, + backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4, 5], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_rsa_512(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import rsa + rsa.generate_private_key(3, + 512, + backends.default_backend()) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(4, issue.lineno) + self.assertEqual([4, 5, 6], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycrypto_dsa_512(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import DSA as pycrypto_dsa + pycrypto_dsa.generate(512) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycrypto_rsa_512(self): + fdata = textwrap.dedent( + """ + from Crypto.PublicKey import RSA as pycrypto_rsa + pycrypto_rsa.generate(512) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycryptodomex_dsa_512(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import DSA as pycryptodomex_dsa + pycryptodomex_dsa.generate(512) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_pycryptodomex_rsa_512(self): + fdata = textwrap.dedent( + """ + from Cryptodome.PublicKey import RSA as pycryptodomex_rsa + pycryptodomex_rsa.generate(512) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.HIGH, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual( + b_issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH, issue.cwe.id + ) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_cryptography_ec_unknown_curve(self): + fdata = textwrap.dedent( + """ + from cryptography.hazmat import backends + from cryptography.hazmat.primitives.asymmetric import ec + ec.generate_private_key( + curve=curves[self.curve]['create'](self.size), + backend=backends.default_backend() + ) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) diff --git a/tests/unit/plugins/test_yaml_load.py b/tests/unit/plugins/test_yaml_load.py new file mode 100644 index 00000000..c16c4e2a --- /dev/null +++ b/tests/unit/plugins/test_yaml_load.py @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: Apache-2.0 +import textwrap + +import bandit +from bandit.core import issue as b_issue +from tests.unit.plugins import base_test_case + + +class YamlLoadTests(base_test_case.BaseTestCase): + def setUp(self): + super().setUp(["B506"]) + + def test_load_with_default_loader(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.load("{}") + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_INPUT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_load_with_safeloader(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.load("{}", Loader=yaml.SafeLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_with_csafeloader(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.load("{}", Loader=yaml.CSafeLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_with_unsafe_loader(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.load("{}", Loader=yaml.Loader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(1, len(self.visitor.tester.results)) + issue = self.visitor.tester.results[0] + self.assertEqual(bandit.MEDIUM, issue.severity) + self.assertEqual(bandit.HIGH, issue.confidence) + self.assertEqual(b_issue.Cwe.IMPROPER_INPUT_VALIDATION, issue.cwe.id) + self.assertEqual(3, issue.lineno) + self.assertEqual([3], issue.linerange) + self.assertEqual(0, issue.col_offset) + + def test_safe_load(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.safe_load("{}") + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_no_import(self): + fdata = 'yaml.load("{}")' + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_safeloader(self): + fdata = textwrap.dedent( + """ + import yaml + from yaml import SafeLoader + yaml.load("{}", SafeLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_yaml_safeloader(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.load("{}", yaml.SafeLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_csafeloader(self): + fdata = textwrap.dedent( + """ + import yaml + from yaml import CSafeLoader + yaml.load("{}", CSafeLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results)) + + def test_load_yaml_csafeloader(self): + fdata = textwrap.dedent( + """ + import yaml + yaml.load("{}", yaml.CSafeLoader) + """ + ) + self.visitor.process(fdata) + self.assertEqual(0, len(self.visitor.tester.results))