From 222c0809b38d2e59b28f7e8042fb2fc6cf2dddd0 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Thu, 10 Dec 2015 18:00:14 -0800 Subject: [PATCH] Use sphinx autodoc to generate docs from docstring Rather than having separate rst documentation files, this patch auto generates the docs from the docstrings in the modules. Should make it easier to maintain. Also renamed directory docs to doc to be consistent with all other OpenStack projects. Change-Id: Iaed77f8358ccb6edaf2627fbabdcc855272b4ea2 --- .gitignore | 4 +- bandit/plugins/app_debug.py | 37 ++ bandit/plugins/asserts.py | 38 ++ bandit/plugins/blacklist_calls.py | 70 +++ bandit/plugins/blacklist_imports.py | 130 +++++- .../crypto_request_no_cert_validation.py | 38 ++ bandit/plugins/exec.py | 29 ++ bandit/plugins/exec_as_root.py | 50 ++ .../plugins/general_bad_file_permissions.py | 45 ++ bandit/plugins/general_bind_all_interfaces.py | 32 ++ bandit/plugins/general_hardcoded_password.py | 43 ++ bandit/plugins/general_hardcoded_tmp.py | 44 ++ bandit/plugins/injection_paramiko.py | 47 ++ bandit/plugins/injection_shell.py | 434 ++++++++++++++++++ bandit/plugins/injection_sql.py | 47 ++ bandit/plugins/injection_wildcard.py | 90 ++++ bandit/plugins/insecure_ssl_tls.py | 167 +++++++ bandit/plugins/jinja2_templates.py | 58 +++ bandit/plugins/mako_templates.py | 41 ++ bandit/plugins/secret_config_option.py | 54 +++ bandit/plugins/try_except_pass.py | 64 +++ bandit/plugins/weak_cryptographic_key.py | 34 ++ {docs => doc}/old/exec.md | 0 {docs => doc}/old/jinja2.md | 0 {docs => doc}/old/partial_paths.md | 0 {docs => doc}/old/ssl_tls.md | 0 {docs => doc}/old/temp.md | 0 {docs => doc}/old/xml.md | 0 {docs => doc}/old/yaml.md | 0 {docs => doc}/source/conf.py | 0 {docs => doc}/source/config.rst | 0 {docs => doc}/source/formatters/index.rst | 0 {docs => doc}/source/index.rst | 2 +- ..._other_function_with_shell_equals_true.rst | 8 + doc/source/plugins/assert_used.rst | 5 + doc/source/plugins/blacklist_calls.rst | 5 + doc/source/plugins/blacklist_import_func.rst | 8 + doc/source/plugins/blacklist_imports.rst | 8 + doc/source/plugins/exec_used.rst | 5 + .../execute_with_run_as_root_equals_true.rst | 5 + doc/source/plugins/flask_debug_true.rst | 5 + .../plugins/hardcoded_bind_all_interfaces.rst | 5 + doc/source/plugins/hardcoded_password.rst | 5 + .../plugins/hardcoded_sql_expressions.rst | 5 + .../plugins/hardcoded_tmp_directory.rst | 5 + .../tests => doc/source/plugins}/index.rst | 0 .../plugins/jinja2_autoescape_false.rst | 5 + .../linux_commands_wildcard_injection.rst | 5 + doc/source/plugins/paramiko_calls.rst | 5 + ...ssword_config_option_not_marked_secret.rst | 5 + .../request_with_no_cert_validation.rst | 5 + .../plugins/set_bad_file_permissions.rst | 5 + doc/source/plugins/ssl_with_bad_defaults.rst | 8 + doc/source/plugins/ssl_with_bad_version.rst | 8 + doc/source/plugins/ssl_with_no_version.rst | 8 + .../plugins/start_process_with_a_shell.rst | 8 + .../plugins/start_process_with_no_shell.rst | 8 + .../start_process_with_partial_path.rst | 8 + ...ubprocess_popen_with_shell_equals_true.rst | 8 + .../subprocess_without_shell_equals_true.rst | 8 + doc/source/plugins/try_except_pass.rst | 5 + doc/source/plugins/use_of_mako_templates.rst | 5 + doc/source/plugins/weak_cryptographic_key.rst | 5 + ..._other_function_with_shell_equals_true.rst | 65 --- docs/source/tests/assert_used.rst | 38 -- docs/source/tests/blacklist_calls.rst | 71 --- docs/source/tests/blacklist_import_func.rst | 55 --- docs/source/tests/blacklist_imports.rst | 87 ---- docs/source/tests/exec_used.rst | 32 -- .../execute_with_run_as_root_equals_true.rst | 51 -- docs/source/tests/flask_debug_true.rst | 39 -- .../tests/hardcoded_bind_all_interfaces.rst | 33 -- docs/source/tests/hardcoded_password.rst | 45 -- .../tests/hardcoded_sql_expressions.rst | 48 -- docs/source/tests/hardcoded_tmp_directory.rst | 45 -- docs/source/tests/jinja2_autoescape_false.rst | 59 --- .../linux_commands_wildcard_injection.rst | 98 ---- docs/source/tests/paramiko_calls.rst | 52 --- ...ssword_config_option_not_marked_secret.rst | 57 --- .../tests/request_with_no_cert_validation.rst | 40 -- .../source/tests/set_bad_file_permissions.rst | 47 -- docs/source/tests/ssl_with_bad_defaults.rst | 57 --- docs/source/tests/ssl_with_bad_version.rst | 83 ---- docs/source/tests/ssl_with_no_version.rst | 59 --- .../tests/start_process_with_a_shell.rst | 73 --- .../tests/start_process_with_no_shell.rst | 76 --- .../tests/start_process_with_partial_path.rst | 74 --- ...ubprocess_popen_with_shell_equals_true.rst | 92 ---- .../subprocess_without_shell_equals_true.rst | 68 --- docs/source/tests/try_except_pass.rst | 66 --- docs/source/tests/use_of_mako_templates.rst | 47 -- docs/source/tests/weak_cryptographic_key.rst | 36 -- setup.cfg | 4 +- 93 files changed, 1774 insertions(+), 1699 deletions(-) rename {docs => doc}/old/exec.md (100%) rename {docs => doc}/old/jinja2.md (100%) rename {docs => doc}/old/partial_paths.md (100%) rename {docs => doc}/old/ssl_tls.md (100%) rename {docs => doc}/old/temp.md (100%) rename {docs => doc}/old/xml.md (100%) rename {docs => doc}/old/yaml.md (100%) rename {docs => doc}/source/conf.py (100%) rename {docs => doc}/source/config.rst (100%) rename {docs => doc}/source/formatters/index.rst (100%) rename {docs => doc}/source/index.rst (97%) create mode 100644 doc/source/plugins/any_other_function_with_shell_equals_true.rst create mode 100644 doc/source/plugins/assert_used.rst create mode 100644 doc/source/plugins/blacklist_calls.rst create mode 100644 doc/source/plugins/blacklist_import_func.rst create mode 100644 doc/source/plugins/blacklist_imports.rst create mode 100644 doc/source/plugins/exec_used.rst create mode 100644 doc/source/plugins/execute_with_run_as_root_equals_true.rst create mode 100644 doc/source/plugins/flask_debug_true.rst create mode 100644 doc/source/plugins/hardcoded_bind_all_interfaces.rst create mode 100644 doc/source/plugins/hardcoded_password.rst create mode 100644 doc/source/plugins/hardcoded_sql_expressions.rst create mode 100644 doc/source/plugins/hardcoded_tmp_directory.rst rename {docs/source/tests => doc/source/plugins}/index.rst (100%) create mode 100644 doc/source/plugins/jinja2_autoescape_false.rst create mode 100644 doc/source/plugins/linux_commands_wildcard_injection.rst create mode 100644 doc/source/plugins/paramiko_calls.rst create mode 100644 doc/source/plugins/password_config_option_not_marked_secret.rst create mode 100644 doc/source/plugins/request_with_no_cert_validation.rst create mode 100644 doc/source/plugins/set_bad_file_permissions.rst create mode 100644 doc/source/plugins/ssl_with_bad_defaults.rst create mode 100644 doc/source/plugins/ssl_with_bad_version.rst create mode 100644 doc/source/plugins/ssl_with_no_version.rst create mode 100644 doc/source/plugins/start_process_with_a_shell.rst create mode 100644 doc/source/plugins/start_process_with_no_shell.rst create mode 100644 doc/source/plugins/start_process_with_partial_path.rst create mode 100644 doc/source/plugins/subprocess_popen_with_shell_equals_true.rst create mode 100644 doc/source/plugins/subprocess_without_shell_equals_true.rst create mode 100644 doc/source/plugins/try_except_pass.rst create mode 100644 doc/source/plugins/use_of_mako_templates.rst create mode 100644 doc/source/plugins/weak_cryptographic_key.rst delete mode 100644 docs/source/tests/any_other_function_with_shell_equals_true.rst delete mode 100644 docs/source/tests/assert_used.rst delete mode 100644 docs/source/tests/blacklist_calls.rst delete mode 100644 docs/source/tests/blacklist_import_func.rst delete mode 100644 docs/source/tests/blacklist_imports.rst delete mode 100644 docs/source/tests/exec_used.rst delete mode 100644 docs/source/tests/execute_with_run_as_root_equals_true.rst delete mode 100644 docs/source/tests/flask_debug_true.rst delete mode 100644 docs/source/tests/hardcoded_bind_all_interfaces.rst delete mode 100644 docs/source/tests/hardcoded_password.rst delete mode 100644 docs/source/tests/hardcoded_sql_expressions.rst delete mode 100644 docs/source/tests/hardcoded_tmp_directory.rst delete mode 100644 docs/source/tests/jinja2_autoescape_false.rst delete mode 100644 docs/source/tests/linux_commands_wildcard_injection.rst delete mode 100644 docs/source/tests/paramiko_calls.rst delete mode 100644 docs/source/tests/password_config_option_not_marked_secret.rst delete mode 100644 docs/source/tests/request_with_no_cert_validation.rst delete mode 100644 docs/source/tests/set_bad_file_permissions.rst delete mode 100644 docs/source/tests/ssl_with_bad_defaults.rst delete mode 100644 docs/source/tests/ssl_with_bad_version.rst delete mode 100644 docs/source/tests/ssl_with_no_version.rst delete mode 100644 docs/source/tests/start_process_with_a_shell.rst delete mode 100644 docs/source/tests/start_process_with_no_shell.rst delete mode 100644 docs/source/tests/start_process_with_partial_path.rst delete mode 100644 docs/source/tests/subprocess_popen_with_shell_equals_true.rst delete mode 100644 docs/source/tests/subprocess_without_shell_equals_true.rst delete mode 100644 docs/source/tests/try_except_pass.rst delete mode 100644 docs/source/tests/use_of_mako_templates.rst delete mode 100644 docs/source/tests/weak_cryptographic_key.rst diff --git a/.gitignore b/.gitignore index bcd88f2f..bf13380f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,8 @@ venv* build/* cover/* .coverage -docs/build/* +doc/build/* ChangeLog -docs/source/api +doc/source/api .*.sw? AUTHORS diff --git a/bandit/plugins/app_debug.py b/bandit/plugins/app_debug.py index 13e2c37f..c90fb65e 100644 --- a/bandit/plugins/app_debug.py +++ b/bandit/plugins/app_debug.py @@ -14,6 +14,43 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Running Flask applications in debug mode results in the Werkzeug debugger +being enabled. This includes a feature that allows arbitrary code execution. +Documentation for both Flask [1]_ and Werkzeug [2]_ strongly suggests that +debug mode should never be enabled on production systems. + +Operating a production server with debug mode enabled was the probable cause +of the Patreon breach in 2015 [3]_. + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: A Flask app appears to be run with debug=True, which exposes + the Werkzeug debugger and allows the execution of arbitrary code. + Severity: High Confidence: High + Location: examples/flask_debug.py:10 + 9 #bad + 10 app.run(debug=True) + 11 + +References +---------- +.. [1] http://flask.pocoo.org/docs/0.10/quickstart/#debug-mode +.. [2] http://werkzeug.pocoo.org/docs/0.10/debug/ +.. [3] http://labs.detectify.com/post/130332638391/how-patreon-got-hacked-publicly-exposed-werkzeug # noqa + +.. versionadded:: 0.15.0 + +""" + import bandit from bandit.core.test_properties import checks diff --git a/bandit/plugins/asserts.py b/bandit/plugins/asserts.py index 4f0ab6e9..245b9863 100644 --- a/bandit/plugins/asserts.py +++ b/bandit/plugins/asserts.py @@ -14,6 +14,44 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +This plugin test checks for the use of the Python ``assert`` keyword. It was +discovered that some projects used assert to enforce interface constraints. +However, assert is removed with compiling to optimised byte code (python -o +producing \*.pyo files). This caused various protections to be removed. The use +of assert is also considered as general bad practice in OpenStack codebases. + +Please see +https://docs.python.org/2/reference/simple_stmts.html#the-assert-statement for +more info on ``assert`` + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: Use of assert detected. The enclosed code will be removed when + compiling to optimised byte code. + Severity: Low Confidence: High + Location: ./examples/assert.py:1 + 1 assert logged_in + 2 display_assets() + +References +---------- + - https://bugs.launchpad.net/juniperopenstack/+bug/1456193 + - https://bugs.launchpad.net/heat/+bug/1397883 + - https://docs.python.org/2/reference/simple_stmts.html#the-assert-statement + +.. versionadded:: 0.11.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/blacklist_calls.py b/bandit/plugins/blacklist_calls.py index 68fee7e3..5cd3375c 100644 --- a/bandit/plugins/blacklist_calls.py +++ b/bandit/plugins/blacklist_calls.py @@ -14,6 +14,76 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +A number of Python methods and functions are known to have potential security +implications. The blacklist calls plugin test is designed to detect the use of +these methods by scanning code for method calls and checking for their presence +in a configurable blacklist. The scanned calls are fully qualified and +de-aliased prior to checking. To illustrate this, imagine a check for +"evil.thing()" running on the following example code: + +.. code-block:: python + + import evil as good + + good.thing() + thing() + +This would generate a warning about calling `evil.thing()` despite the module +being aliased as `good`. It would also not generate a warning on the call to +`thing()` in the local module, as it's fully qualified name will not match. + +Each of the provided blacklisted calls can be grouped such that they generate +appropriate warnings (message, severity) and a token `{func}` may be used +in the provided output message, to be replaced with the actual method name. + +Due to the nature of the test, confidence is always reported as HIGH + +Config Options +-------------- +.. code-block:: yaml + + blacklist_calls: + bad_name_sets: + - pickle: + qualnames: + - pickle.loads + - pickle.load + - pickle.Unpickler + - cPickle.loads + - cPickle.load + - cPickle.Unpickler + message: > + Pickle library appears to be in use, possible security + issue. + - marshal: + qualnames: [marshal.load, marshal.loads] + message: > + Deserialization with the {func} is possibly dangerous. + level: LOW + +Sample Output +------------- +.. code-block:: none + + >> Issue: Pickle library appears to be in use, possible security issue. + + Severity: Medium Confidence: High + Location: ./examples/pickle_deserialize.py:20 + 19 serialized = cPickle.dumps({(): []}) + 20 print(cPickle.loads(serialized)) + 21 + +References +---------- +- https://security.openstack.org + +.. versionadded:: 0.9.0 + +""" + import fnmatch import bandit diff --git a/bandit/plugins/blacklist_imports.py b/bandit/plugins/blacklist_imports.py index 5962a541..a1623d0b 100644 --- a/bandit/plugins/blacklist_imports.py +++ b/bandit/plugins/blacklist_imports.py @@ -14,7 +14,6 @@ # License for the specific language governing permissions and limitations # under the License. - import bandit from bandit.core.test_properties import * @@ -22,6 +21,89 @@ from bandit.core.test_properties import * @takes_config @checks('Import', 'ImportFrom') def blacklist_imports(context, config): + """blacklist_imports + + A number of Python modules are known to provide collections of + functionality with potential security implications. The blacklist imports + plugin test is designed to detect the use of these modules by scanning code + for `import` statements and checking for the imported modules presence in a + configurable blacklist. The imported modules are fully qualified and + de-aliased prior to checking. To illustrate this, imagine a check for + "module.evil" running on the following example code: + + .. code-block:: python + + import module # no warning + import module.evil # warning + from module import evil # warning + from module import evil as good # warning + + This would generate a warning about importing `module.evil` in each of the + last three cases, despite the module being aliased as `good` in one of + them. It would also not generate a warning on the first import + (of `module`) as it's fully qualified name will not match. + + Each of the provided blacklisted modules can be grouped such that they + generate appropriate warnings (message, severity) and a token `{module}` + may be used in the provided output message, to be replaced with the actual + module name. + + Due to the nature of the test, confidence is always reported as HIGH + + Config Options: + + .. code-block:: yaml + + blacklist_imports: + bad_import_sets: + - xml_libs: + imports: + - xml.etree.cElementTree + - xml.etree.ElementTree + - xml.sax.expatreader + - xml.sax + - xml.dom.expatbuilder + - xml.dom.minidom + - xml.dom.pulldom + - lxml.etree + - lxml + message: > + Using {module} to parse untrusted XML data is known to + be vulnerable to XML attacks. Replace {module} with the + equivalent defusedxml package. + level: LOW + + + Sample Output: + + .. code-block:: none + + >> Issue: Using xml.sax to parse untrusted XML data is known to be + vulnerable to XML attacks. Replace xml.sax with the equivalent + defusedxml package. + + Severity: Low Confidence: High + Location: ./examples/xml_sax.py:1 + 1 import xml.sax + 2 from xml import sax + + >> Issue: Using xml.sax.parseString to parse untrusted XML data is + known to be vulnerable to XML attacks. Replace xml.sax.parseString with + its defusedxml equivalent function. + + Severity: Medium Confidence: High + Location: ./examples/xml_sax.py:21 + 20 # bad + 21 xml.sax.parseString(xmlString, ExampleContentHandler()) + 22 xml.sax.parse('notaxmlfilethatexists.xml', ExampleContentHandler()) + + References: + + - https://security.openstack.org + + .. versionadded:: 0.9.0 + """ + checks = _load_checks(config) # for each check, go through and see if it matches all qualifications @@ -36,6 +118,52 @@ def blacklist_imports(context, config): @takes_config('blacklist_imports') @checks('Call') def blacklist_import_func(context, config): + """blacklist_import_func + + This test is in all ways identical blacklist_imports. However, it + is designed to catch modules that have been imported using Python's special + builtin import function, `__import__()`. For example, running a test on the + following code for `module.evil` would warn as shown: + + .. code-block:: python + + __import__('module') # no warning + __import__('module.evil') # warning + + This test shares the configuration provided for the standard + blacklist_imports test. + + + Sample Output: + + .. code-block:: none + + >> Issue: Using xml.sax to parse untrusted XML data is known to be + vulnerable to XML attacks. Replace xml.sax with the equivalent + defusedxml package. + + Severity: Low Confidence: High + Location: ./examples/xml_sax.py:1 + 1 import xml.sax + 2 from xml import sax + + >> Issue: Using xml.sax.parseString to parse untrusted XML data is + known to be vulnerable to XML attacks. Replace xml.sax.parseString with + its defusedxml equivalent function. + + Severity: Medium Confidence: High + Location: ./examples/xml_sax.py:21 + 20 # bad + 21 xml.sax.parseString(xmlString, ExampleContentHandler()) + 22 xml.sax.parse('notaxmlfilethatexists.xml', ExampleContentHandler()) + + + References: + + - https://security.openstack.org + + .. versionadded:: 0.9.0 + """ checks = _load_checks(config) if context.call_function_name_qual == '__import__': for check in checks: diff --git a/bandit/plugins/crypto_request_no_cert_validation.py b/bandit/plugins/crypto_request_no_cert_validation.py index d982d949..e8c0e72b 100644 --- a/bandit/plugins/crypto_request_no_cert_validation.py +++ b/bandit/plugins/crypto_request_no_cert_validation.py @@ -14,6 +14,44 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Encryption in general is typically critical to the security of many +applications. Using TLS can greatly increase security by guaranteeing the +identity of the party you are communicating with. This is accomplished by one +or both parties presenting trusted certificates during the connection +initialization phase of TLS. + +When request methods are used certificates are validated automatically which is +the desired behavior. If certificate validation is explicitly turned off +Bandit will return a HIGH severity error. + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: [request_with_no_cert_validation] Requests call with verify=False + disabling SSL certificate checks, security issue. + Severity: High Confidence: High + Location: examples/requests-ssl-verify-disabled.py:4 + 3 requests.get('https://gmail.com', verify=True) + 4 requests.get('https://gmail.com', verify=False) + 5 requests.post('https://gmail.com', verify=True) + +References +---------- +- https://security.openstack.org/guidelines/dg_move-data-securely.html +- https://security.openstack.org/guidelines/dg_validate-certificates.html + +.. versionadded:: 0.9.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/exec.py b/bandit/plugins/exec.py index 3e55c9d8..6ce777bd 100644 --- a/bandit/plugins/exec.py +++ b/bandit/plugins/exec.py @@ -13,6 +13,35 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + +r""" +Description +----------- +This plugin test checks for the use of Python's `exec` method or keyword. The +Python docs succinctly describe why the use of `exec` is risky. + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: Use of exec detected. + Severity: Medium Confidence: High + Location: ./examples/exec-py2.py:2 + 1 exec("do evil") + 2 exec "do evil" + +References +---------- + - https://docs.python.org/2.0/ref/exec.html + - TODO: add info on exec and similar to sec best practice and link here + +.. versionadded:: 0.9.0 +""" + import six import bandit diff --git a/bandit/plugins/exec_as_root.py b/bandit/plugins/exec_as_root.py index 5763da37..88329f44 100644 --- a/bandit/plugins/exec_as_root.py +++ b/bandit/plugins/exec_as_root.py @@ -12,6 +12,56 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Running commands as root dramatically increase their potential risk. Running +commands with restricted user privileges provides defense in depth against +command injection attacks, or developer and configuration error. This plugin +test checks for specific methods being called with a keyword parameter +`run_as_root` set to True, a common OpenStack idiom. + + +Config Options +-------------- +This test plugin takes a similarly named configuration block, +`execute_with_run_as_root_equals_true`, providing a list, `function_names`, of +function names. A call to any of these named functions will be checked for a +`run_as_root` keyword parameter, and if True, will report a Low severity +issue. + +.. code-block:: yaml + + execute_with_run_as_root_equals_true: + function_names: + - ceilometer.utils.execute + - cinder.utils.execute + - neutron.agent.linux.utils.execute + - nova.utils.execute + - nova.utils.trycmd + + +Sample Output +------------- +.. code-block:: none + + >> Issue: Execute with run_as_root=True identified, possible security + issue. + Severity: Low Confidence: Medium + Location: ./examples/exec-as-root.py:26 + 25 nova_utils.trycmd('gcc --version') + 26 nova_utils.trycmd('gcc --version', run_as_root=True) + 27 + +References +---------- + - https://security.openstack.org/guidelines/dg_rootwrap-recommendations-and-plans.html # noqa + - https://security.openstack.org/guidelines/dg_use-oslo-rootwrap-securely.html + +.. versionadded:: 0.10.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/general_bad_file_permissions.py b/bandit/plugins/general_bad_file_permissions.py index 5a39c00d..7a14d82b 100644 --- a/bandit/plugins/general_bad_file_permissions.py +++ b/bandit/plugins/general_bad_file_permissions.py @@ -14,6 +14,51 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +POSIX based operating systems utilize a permissions model to protect access to +parts of the file system. This model supports three roles "owner", "group" +and "world" each role may have a combination of "read", "write" or "execute" +flags sets. Python provides ``chmod`` to manipulate POSIX style permissions. + +This plugin test looks for the use of ``chmod`` and will alert when it is used +to set particularly permissive control flags. A MEDIUM warning is generated if +a file is set to group executable and a HIGH warning is reported if a file is +set world writable. Warnings are given with HIGH confidence. + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: Probable insecure usage of temp file/directory. + Severity: Medium Confidence: Medium + Location: ./examples/os-chmod-py2.py:15 + 14 os.chmod('/etc/hosts', 0o777) + 15 os.chmod('/tmp/oh_hai', 0x1ff) + 16 os.chmod('/etc/passwd', stat.S_IRWXU) + + >> Issue: Chmod setting a permissive mask 0777 on file (key_file). + Severity: High Confidence: High + Location: ./examples/os-chmod-py2.py:17 + 16 os.chmod('/etc/passwd', stat.S_IRWXU) + 17 os.chmod(key_file, 0o777) + 18 + +References +---------- +- https://security.openstack.org/guidelines/dg_apply-restrictive-file-permissions.html # noqa +- https://en.wikipedia.org/wiki/File_system_permissions +- https://security.openstack.org + +.. versionadded:: 0.9.0 + +""" + import stat import bandit diff --git a/bandit/plugins/general_bind_all_interfaces.py b/bandit/plugins/general_bind_all_interfaces.py index 97a811fc..229f03b7 100644 --- a/bandit/plugins/general_bind_all_interfaces.py +++ b/bandit/plugins/general_bind_all_interfaces.py @@ -14,6 +14,38 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Binding to all network interfaces can potentially open up a service to traffic +on unintended interfaces, that may not be properly documented or secured. This +plugin test looks for a string pattern "0.0.0.0" that may indicate a hardcoded +binding to all network interfaces. + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: Possible binding to all interfaces. + Severity: Medium Confidence: Medium + Location: ./examples/binding.py:4 + 3 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + 4 s.bind(('0.0.0.0', 31137)) + 5 s.bind(('192.168.0.1', 8080)) + +References +---------- + - __TODO__ : add best practice info on binding to all interfaces, and link + here. + +.. versionadded:: 0.9.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 2915066f..b5e2e972 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -14,6 +14,49 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +The use of hard-coded passwords increases the possibility of password guessing +tremendously. This plugin test looks for all string literals and checks to see +if they exist in a list of likely default passwords. If they are found in the +list, a LOW severity issue is reported. + +Note: this test is very noisy and likely to result in many false positives. + +Config Options +-------------- +This plugin test takes a similarly named config block, `hardcoded_password`. +Here a path, `word_list`, can be given to indicate where the default password +word list file may be found. + +.. code-block:: yaml + + hardcoded_password: + # Support for full path, relative path and special "%(site_data_dir)s" + # substitution (/usr/{local}/share) + word_list: "%(site_data_dir)s/wordlist/default-passwords" + + +Sample Output +------------- +.. code-block:: none + + >> Issue: Possible hardcoded password '(root)' + Severity: Low Confidence: Low + Location: ./examples/hardcoded-passwords.py:5 + 4 def someFunction2(password): + 5 if password == "root": + 6 print("OK, logged in") + +References +---------- +- https://www.owasp.org/index.php/Use_of_hard-coded_password + +.. versionadded:: 0.9.0 + +""" + import sys import bandit diff --git a/bandit/plugins/general_hardcoded_tmp.py b/bandit/plugins/general_hardcoded_tmp.py index eb54f86b..5ad62619 100644 --- a/bandit/plugins/general_hardcoded_tmp.py +++ b/bandit/plugins/general_hardcoded_tmp.py @@ -14,6 +14,50 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Safely creating a temporary file or directory means following a number of rules +(see the references for more details). This plugin test looks for strings +starting with (configurable) commonly used temporary paths, for example: + + - /tmp + - /var/tmp + - /dev/shm + - etc + +Config Options +-------------- +This test plugin takes a similarly named config block, +`hardcoded_tmp_directory`. The config block provides a Python list, `tmp_dirs`, +that lists string fragments indicating possible temporary file paths. Any +string starting with one of these fragments will report a MEDIUM confidence +issue. + +.. code-block:: yaml + + hardcoded_tmp_directory: + tmp_dirs: ['/tmp', '/var/tmp', '/dev/shm'] + + +Sample Output +------------- +.. code-block: none + + >> Issue: Probable insecure usage of temp file/directory. + Severity: Medium Confidence: Medium + Location: ./examples/hardcoded-tmp.py:1 + 1 f = open('/tmp/abc', 'w') + 2 f.write('def') + +References +---------- + - https://security.openstack.org/guidelines/dg_using-temporary-files-securely.html # noqa + +.. versionadded:: 0.9.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/injection_paramiko.py b/bandit/plugins/injection_paramiko.py index 57ce92d7..8a760668 100644 --- a/bandit/plugins/injection_paramiko.py +++ b/bandit/plugins/injection_paramiko.py @@ -14,6 +14,53 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Paramiko is a Python library designed to work with the SSH2 protocol for secure +(encrypted and authenticated) connections to remote machines. It is intended to +run commands on a remote host. These commands are run within a shell on the +target and are thus vulnerable to various shell injection attacks. Bandit +reports a MEDIUM issue when it detects the use of Paramiko's "exec_command" or +"invoke_shell" methods advising the user to check inputs are correctly +sanitized. + + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: Possible shell injection via Paramiko call, check inputs are + properly sanitized. + Severity: Medium Confidence: Medium + Location: ./examples/paramiko_injection.py:4 + 3 # this is not safe + 4 paramiko.exec_command('something; reallly; unsafe') + 5 + + >> Issue: Possible shell injection via Paramiko call, check inputs are + properly sanitized. + Severity: Medium Confidence: Medium + Location: ./examples/paramiko_injection.py:10 + 9 # this is not safe + 10 SSHClient.invoke_shell('something; bad; here\n') + 11 + +References +---------- + +- https://security.openstack.org +- https://github.com/paramiko/paramiko +- https://www.owasp.org/index.php/Command_Injection + +.. versionadded:: 0.12.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/injection_shell.py b/bandit/plugins/injection_shell.py index edbac57b..72144157 100644 --- a/bandit/plugins/injection_shell.py +++ b/bandit/plugins/injection_shell.py @@ -50,6 +50,96 @@ def _evaluate_shell_call(context): @takes_config('shell_injection') @checks('Call') def subprocess_popen_with_shell_equals_true(context, config): + """subprocess_popen_with_shell_equals_true + + Python possesses many mechanisms to invoke an external executable. However, + doing so may present a security issue if appropriate care is not taken to + sanitize any user provided or variable input. + + This plugin test is part of a family of tests built to check for process + spawning and warn appropriately. Specifically, this test looks for the + spawning of a subprocess using a command shell. This type of subprocess + invocation is dangerous as it is vulnerable to various shell injection + attacks. Great care should be taken to sanitize all input in order to + mitigate this risk. Calls of this type are identified by a parameter of + "shell=True" being given. + + Additionally, this plugin scans the command string given and adjusts its + reported severity based on how it is presented. If the command string is a + simple static string containing no special shell characters, then the + resulting issue has low severity. If the string is static, but contains + shell formatting characters or wildcards, then the reported issue is + medium. Finally, if the string is computed using Python's string + manipulation or formatting operations, then the reported issue has high + severity. These severity levels reflect the likelihood that the code is + vulnerable to injection. + + See also: + + - :doc:`../plugins/linux_commands_wildcard_injection` + - :doc:`../plugins/subprocess_without_shell_equals_true` + - :doc:`../plugins/start_process_with_no_shell` + - :doc:`../plugins/start_process_with_a_shell` + - :doc:`../plugins/start_process_with_partial_path` + + Config Options: + + This plugin test shares a configuration with others in the same family, + namely `shell_injection`. This configuration is divided up into three + sections, `subprocess`, `shell` and `no_shell`. They each list Python calls + that spawn subprocesses, invoke commands within a shell, or invoke commands + without a shell (by replacing the calling process) respectively. + + This plugin specifically scans for methods listed in `subprocess` section + that have shell=True specified. + + .. code-block:: yaml + + shell_injection: + + # Start a process using the subprocess module, or one of its + wrappers. + subprocess: + - subprocess.Popen + - subprocess.call + + + Sample Output: + + .. code-block:: none + + >> Issue: subprocess call with shell=True seems safe, but may be + changed in the future, consider rewriting without shell + Severity: Low Confidence: High + Location: ./examples/subprocess_shell.py:21 + 20 subprocess.check_call(['/bin/ls', '-l'], shell=False) + 21 subprocess.check_call('/bin/ls -l', shell=True) + 22 + + >> Issue: call with shell=True contains special shell characters, + consider moving extra logic into Python code + Severity: Medium Confidence: High + Location: ./examples/subprocess_shell.py:26 + 25 + 26 subprocess.Popen('/bin/ls *', shell=True) + 27 subprocess.Popen('/bin/ls %s' % ('something',), shell=True) + + >> Issue: subprocess call with shell=True identified, security issue. + Severity: High Confidence: High + Location: ./examples/subprocess_shell.py:27 + 26 subprocess.Popen('/bin/ls *', shell=True) + 27 subprocess.Popen('/bin/ls %s' % ('something',), shell=True) + 28 subprocess.Popen('/bin/ls {}'.format('something'), shell=True) + + References: + + - https://security.openstack.org + - https://docs.python.org/2/library/subprocess.html#frequently-used-arguments # noqa + - https://security.openstack.org/guidelines/dg_use-subprocess-securely.html + - https://security.openstack.org/guidelines/dg_avoid-shell-true.html + + .. versionadded:: 0.9.0 + """ if config and context.call_function_name_qual in config['subprocess']: if context.check_call_arg_value('shell', 'True'): if len(context.call_args) > 0: @@ -82,6 +172,71 @@ def subprocess_popen_with_shell_equals_true(context, config): @takes_config('shell_injection') @checks('Call') def subprocess_without_shell_equals_true(context, config): + """subprocess_without_shell_equals_true + + Python possesses many mechanisms to invoke an external executable. However, + doing so may present a security issue if appropriate care is not taken to + sanitize any user provided or variable input. + + This plugin test is part of a family of tests built to check for process + spawning and warn appropriately. Specifically, this test looks for the + spawning of a subprocess without the use of a command shell. This type of + subprocess invocation is not vulnerable to shell injection attacks, but + care should still be taken to ensure validity of input. + + Because this is a lesser issue than that described in + `subprocess_popen_with_shell_equals_true` a LOW severity warning is + reported. + + See also: + + - :doc:`../plugins/linux_commands_wildcard_injection` + - :doc:`../plugins/subprocess_popen_with_shell_equals_true` + - :doc:`../plugins/start_process_with_no_shell` + - :doc:`../plugins/start_process_with_a_shell` + - :doc:`../plugins/start_process_with_partial_path` + + Config Options: + + This plugin test shares a configuration with others in the same family, + namely `shell_injection`. This configuration is divided up into three + sections, `subprocess`, `shell` and `no_shell`. They each list Python calls + that spawn subprocesses, invoke commands within a shell, or invoke commands + without a shell (by replacing the calling process) respectively. + + This plugin specifically scans for methods listed in `subprocess` section + that have shell=False specified. + + .. code-block:: yaml + + shell_injection: + # Start a process using the subprocess module, or one of its + wrappers. + subprocess: + - subprocess.Popen + - subprocess.call + + + Sample Output: + + .. code-block:: none + + >> Issue: subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + Location: ./examples/subprocess_shell.py:23 + 22 + 23 subprocess.check_output(['/bin/ls', '-l']) + 24 + + References: + + - https://security.openstack.org + - https://docs.python.org/2/library/subprocess.html#frequently-used-arguments # noqa + - https://security.openstack.org/guidelines/dg_avoid-shell-true.html + - https://security.openstack.org/guidelines/dg_use-subprocess-securely.html + + .. versionadded:: 0.9.0 + """ if config and context.call_function_name_qual in config['subprocess']: if not context.check_call_arg_value('shell', 'True'): return bandit.Issue( @@ -95,10 +250,73 @@ def subprocess_without_shell_equals_true(context, config): @takes_config('shell_injection') @checks('Call') def any_other_function_with_shell_equals_true(context, config): + """any_other_function_with_shell_equals_true + + Python possesses many mechanisms to invoke an external executable. However, + doing so may present a security issue if appropriate care is not taken to + sanitize any user provided or variable input. + + This plugin test is part of a family of tests built to check for process + spawning and warn appropriately. Specifically, this plugin test + interrogates method calls for the presence of a keyword parameter `shell` + equalling true. It is related to detection of shell injection issues and is + intended to catch custom wrappers to vulnerable methods that may have been + created. + + See also: + + - :doc:`../plugins/linux_commands_wildcard_injection` + - :doc:`../plugins/subprocess_popen_with_shell_equals_true` + - :doc:`../plugins/subprocess_without_shell_equals_true` + - :doc:`../plugins/start_process_with_no_shell` + - :doc:`../plugins/start_process_with_a_shell` + - :doc:`../plugins/start_process_with_partial_path` + + Config Options: + + This plugin test shares a configuration with others in the same family, + namely `shell_injection`. This configuration is divided up into three + sections, `subprocess`, `shell` and `no_shell`. They each list Python calls + that spawn subprocesses, invoke commands within a shell, or invoke commands + without a shell (by replacing the calling process) respectively. + + Specifically, this plugin excludes those functions listed under the + subprocess section, these methods are tested in a separate specific test + plugin and this exclusion prevents duplicate issue reporting. + + .. code-block:: yaml + + shell_injection: + # Start a process using the subprocess module, or one of its + wrappers. + subprocess: [subprocess.Popen, subprocess.call, + subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] + + + Sample Output: + + .. code-block:: none + + >> Issue: Function call with shell=True parameter identified, possible + security issue. + Severity: Medium Confidence: High + Location: ./examples/subprocess_shell.py:9 + 8 pop('/bin/gcc --version', shell=True) + 9 Popen('/bin/gcc --version', shell=True) + 10 + + References: + + - https://security.openstack.org/guidelines/dg_avoid-shell-true.html + - https://security.openstack.org/guidelines/dg_use-subprocess-securely.html # noqa + """ '''Alerts on any function call that includes a shell=True parameter. Multiple "helpers" with varying names have been identified across various OpenStack projects. + + .. versionadded:: 0.9.0 ''' if config and context.call_function_name_qual not in config['subprocess']: if context.check_call_arg_value('shell', 'True'): @@ -113,6 +331,75 @@ def any_other_function_with_shell_equals_true(context, config): @takes_config('shell_injection') @checks('Call') def start_process_with_a_shell(context, config): + """start_process_with_a_shell + + Python possesses many mechanisms to invoke an external executable. However, + doing so may present a security issue if appropriate care is not taken to + sanitize any user provided or variable input. + + This plugin test is part of a family of tests built to check for process + spawning and warn appropriately. Specifically, this test looks for the + spawning of a subprocess using a command shell. This type of subprocess + invocation is dangerous as it is vulnerable to various shell injection + attacks. Great care should be taken to sanitize all input in order to + mitigate this risk. Calls of this type are identified by the use of certain + commands which are known to use shells. Bandit will report a MEDIUM + severity warning. + + See also: + + - :doc:`../plugins/linux_commands_wildcard_injection` + - :doc:`../plugins/subprocess_without_shell_equals_true` + - :doc:`../plugins/start_process_with_no_shell` + - :doc:`../plugins/start_process_with_partial_path` + - :doc:`../plugins/subprocess_popen_with_shell_equals_true` + + Config Options: + + This plugin test shares a configuration with others in the same family, + namely `shell_injection`. This configuration is divided up into three + sections, `subprocess`, `shell` and `no_shell`. They each list Python calls + that spawn subprocesses, invoke commands within a shell, or invoke commands + without a shell (by replacing the calling process) respectively. + + This plugin specifically scans for methods listed in `shell` section. + + .. code-block:: yaml + + shell_injection: + shell: + - os.system + - os.popen + - os.popen2 + - os.popen3 + - os.popen4 + - popen2.popen2 + - popen2.popen3 + - popen2.popen4 + - popen2.Popen3 + - popen2.Popen4 + - commands.getoutput + - commands.getstatusoutput + + Sample Output: + + .. code-block:: none + + >> Issue: Starting a process with a shell: check for injection. + Severity: Medium Confidence: Medium + Location: examples/os_system.py:3 + 2 + 3 os.system('/bin/echo hi') + + References: + + - https://security.openstack.org + - https://docs.python.org/2/library/os.html#os.system + - https://docs.python.org/2/library/subprocess.html#frequently-used-arguments # noqa + - https://security.openstack.org/guidelines/dg_use-subprocess-securely.html + + .. versionadded:: 0.10.0 + """ if config and context.call_function_name_qual in config['shell']: if len(context.call_args) > 0: sev = _evaluate_shell_call(context) @@ -144,6 +431,81 @@ def start_process_with_a_shell(context, config): @takes_config('shell_injection') @checks('Call') def start_process_with_no_shell(context, config): + """start_process_with_no_shell + + Python possesses many mechanisms to invoke an external executable. However, + doing so may present a security issue if appropriate care is not taken to + sanitize any user provided or variable input. + + This plugin test is part of a family of tests built to check for process + spawning and warn appropriately. Specifically, this test looks for the + spawning of a subprocess in a way that doesn't use a shell. Although this + is generally safe, it maybe useful for penetration testing workflows to + track where external system calls are used. As such a LOW severity message + is generated. + + See also: + + - :doc:`../plugins/linux_commands_wildcard_injection` + - :doc:`../plugins/subprocess_without_shell_equals_true` + - :doc:`../plugins/start_process_with_a_shell` + - :doc:`../plugins/start_process_with_partial_path` + - :doc:`../plugins/subprocess_popen_with_shell_equals_true` + + Config Options: + + This plugin test shares a configuration with others in the same family, + namely `shell_injection`. This configuration is divided up into three + sections, `subprocess`, `shell` and `no_shell`. They each list Python calls + that spawn subprocesses, invoke commands within a shell, or invoke commands + without a shell (by replacing the calling process) respectively. + + This plugin specifically scans for methods listed in `no_shell` section. + + .. code-block:: yaml + + shell_injection: + no_shell: + - os.execl + - os.execle + - os.execlp + - os.execlpe + - os.execv + - os.execve + - os.execvp + - os.execvpe + - os.spawnl + - os.spawnle + - os.spawnlp + - os.spawnlpe + - os.spawnv + - os.spawnve + - os.spawnvp + - os.spawnvpe + - os.startfile + + Sample Output: + + .. code-block:: none + + >> Issue: [start_process_with_no_shell] Starting a process without a + shell. + Severity: Low Confidence: Medium + Location: examples/os-spawn.py:8 + 7 os.spawnv(mode, path, args) + 8 os.spawnve(mode, path, args, env) + 9 os.spawnvp(mode, file, args) + + References: + + - https://security.openstack.org + - https://docs.python.org/2/library/os.html#os.system + - https://docs.python.org/2/library/subprocess.html#frequently-used-arguments # noqa + - https://security.openstack.org/guidelines/dg_use-subprocess-securely.html + + .. versionadded:: 0.10.0 + """ + if config and context.call_function_name_qual in config['no_shell']: return bandit.Issue( severity=bandit.LOW, @@ -155,6 +517,78 @@ def start_process_with_no_shell(context, config): @takes_config('shell_injection') @checks('Call') def start_process_with_partial_path(context, config): + """start_process_with_partial_path + + Python possesses many mechanisms to invoke an external executable. If the + desired executable path is not fully qualified relative to the filesystem + root then this may present a potential security risk. + + In POSIX environments, the `PATH` environment variable is used to specify a + set of standard locations that will be searched for the first matching + named executable. While convenient, this behavior may allow a malicious + actor to exert control over a system. If they are able to adjust the + contents of the `PATH` variable, or manipulate the file system, then a + bogus executable may be discovered in place of the desired one. This + executable will be invoked with the user privileges of the Python process + that spawned it, potentially a highly privileged user. + + This test will scan the parameters of all configured Python methods, + looking for paths that do not start at the filesystem root, that is, do not + have a leading '/' character. + + Config Options: + + This plugin test shares a configuration with others in the same family, + namely `shell_injection`. This configuration is divided up into three + sections, `subprocess`, `shell` and `no_shell`. They each list Python calls + that spawn subprocesses, invoke commands within a shell, or invoke commands + without a shell (by replacing the calling process) respectively. + + This test will scan parameters of all methods in all sections. Note that + methods are fully qualified and de-aliased prior to checking. + + .. code-block:: yaml + + shell_injection: + # Start a process using the subprocess module, or one of its + wrappers. + subprocess: + - subprocess.Popen + - subprocess.call + + # Start a process with a function vulnerable to shell injection. + shell: + - os.system + - os.popen + - popen2.Popen3 + - popen2.Popen4 + - commands.getoutput + - commands.getstatusoutput + # Start a process with a function that is not vulnerable to shell + injection. + no_shell: + - os.execl + - os.execle + + + Sample Output: + + .. code-block:: none + + >> Issue: Starting a process with a partial executable path + Severity: Low Confidence: High + Location: ./examples/partial_path_process.py:3 + 2 from subprocess import Popen as pop + 3 pop('gcc --version', shell=False) + + References: + + - https://security.openstack.org + - https://docs.python.org/2/library/os.html#process-management + + .. versionadded:: 0.13.0 + """ + if config and len(context.call_args): if(context.call_function_name_qual in config['subprocess'] or context.call_function_name_qual in config['shell'] or diff --git a/bandit/plugins/injection_sql.py b/bandit/plugins/injection_sql.py index e3d1fc8d..be94cb80 100644 --- a/bandit/plugins/injection_sql.py +++ b/bandit/plugins/injection_sql.py @@ -14,6 +14,53 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +An SQL injection attack consists of insertion or "injection" of a SQL query via +the input data given to an application. It is a very common attack vector. This +plugin test looks for strings that resemble SQL statements that are involved in +some form of string building operation. For example: + + - "SELECT %s FROM derp;" % var + - "SELECT thing FROM " + tab + - "SELECT " + val + " FROM " + tab + ... + +Unless care is taken to sanitize and control the input data when building such +SQL statement strings, an injection attack becomes possible. If strings of this +nature are discovered, a LOW confidence issue is reported. In order to boost +result confidence, this plugin test will also check to see if the discovered +string is in use with standard Python DBAPI calls `execute` or `executemany`. +If so, a MEDIUM issue is reported. For example: + + - cursor.execute("SELECT %s FROM derp;" % var) + +Config Options +-------------- +None + + +Sample Output +------------- +.. code-block:: none + + >> Issue: Possible SQL injection vector through string-based query + construction. + Severity: Medium Confidence: Low + Location: ./examples/sql_statements_without_sql_alchemy.py:4 + 3 query = "DELETE FROM foo WHERE id = '%s'" % identifier + 4 query = "UPDATE foo SET value = 'b' WHERE id = '%s'" % identifier + 5 + +References +---------- +- https://www.owasp.org/index.php/SQL_Injection +- https://security.openstack.org/guidelines/dg_parameterize-database-queries.html # noqa + +.. versionadded:: 0.9.0 + +""" + import ast import bandit diff --git a/bandit/plugins/injection_wildcard.py b/bandit/plugins/injection_wildcard.py index 59a9ddde..7e65ddbb 100644 --- a/bandit/plugins/injection_wildcard.py +++ b/bandit/plugins/injection_wildcard.py @@ -14,6 +14,96 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Python provides a number of methods that emulate the behavior of standard Linux +command line utilities. Like their Linux counterparts, these commands may take +a wildcard "\*" character in place of a file system path. This is interpreted +to mean "any and all files or folders" and can be used to build partially +qualified paths, such as "/home/user/\*". + +The use of partially qualified paths may result in unintended consequences if +an unexpected file or symlink is placed into the path location given. This +becomes particularly dangerous when combined with commands used to manipulate +file permissions or copy data off of a system. + +This test plugin looks for usage of the following commands in conjunction with +wild card parameters: + +- 'chown' +- 'chmod' +- 'tar' +- 'rsync' + +As well as any method configured in the shell or subprocess injection test +configurations. + + +Config Options +-------------- +This plugin test shares a configuration with others in the same family, namely +`shell_injection`. This configuration is divided up into three sections, +`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn +subprocesses, invoke commands within a shell, or invoke commands without a +shell (by replacing the calling process) respectively. + +This test will scan parameters of all methods in all sections. Note that +methods are fully qualified and de-aliased prior to checking. + + +.. code-block:: yaml + + shell_injection: + # Start a process using the subprocess module, or one of its wrappers. + subprocess: + - subprocess.Popen + - subprocess.call + + # Start a process with a function vulnerable to shell injection. + shell: + - os.system + - os.popen + - popen2.Popen3 + - popen2.Popen4 + - commands.getoutput + - commands.getstatusoutput + # Start a process with a function that is not vulnerable to shell + injection. + no_shell: + - os.execl + - os.execle + + +Sample Output +------------- +.. code-block:: none + + >> Issue: Possible wildcard injection in call: subprocess.Popen + Severity: High Confidence: Medium + Location: ./examples/wildcard-injection.py:8 + 7 o.popen2('/bin/chmod *') + 8 subp.Popen('/bin/chown *', shell=True) + 9 + + >> Issue: subprocess call - check for execution of untrusted input. + Severity: Low Confidence: High + Location: ./examples/wildcard-injection.py:11 + 10 # Not vulnerable to wildcard injection + 11 subp.Popen('/bin/rsync *') + 12 subp.Popen("/bin/chmod *") + + +References +---------- +- https://security.openstack.org +- https://en.wikipedia.org/wiki/Wildcard_character +- http://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt + +.. versionadded:: 0.9.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/insecure_ssl_tls.py b/bandit/plugins/insecure_ssl_tls.py index b23c90b7..4eff86bd 100644 --- a/bandit/plugins/insecure_ssl_tls.py +++ b/bandit/plugins/insecure_ssl_tls.py @@ -25,6 +25,83 @@ def get_bad_proto_versions(config): @takes_config @checks('Call') def ssl_with_bad_version(context, config): + """Test for SSL use with bad version used + + Several highly publicized exploitable flaws have been discovered + in all versions of SSL and early versions of TLS. It is strongly + recommended that use of the following known broken protocol versions be + avoided: + + - SSL v2 + - SSL v3 + - TLS v1 + - TLS v1.1 + + This plugin test scans for calls to Python methods with parameters that + indicate the used broken SSL/TLS protocol versions. Currently, detection + supports methods using Python's native SSL/TLS support and the pyOpenSSL + module. A HIGH severity warning will be reported whenever known broken + protocol versions are detected. + + It is worth noting that native support for TLS 1.2 is only available in + more recent Python versions, specifically 2.7.9 and up, and 3.x + + See also: + + - :doc:`../plugins/ssl_with_bad_defaults` + - :doc:`../plugins/ssl_with_no_version` + + A note on 'SSLv23': + + Amongst the available SSL/TLS versions provided by Python/pyOpenSSL there + exists the option to use SSLv23. This very poorly named option actually + means "use the highest version of SSL/TLS supported by both the server and + client". This may (and should be) a version well in advance of SSL v2 or + v3. Bandit can scan for the use of SSLv23 if desired, but its detection + does not necessarily indicate a problem. + + When using SSLv23 it is important to also provide flags to explicitly + exclude bad versions of SSL/TLS from the protocol versions considered. Both + the Python native and pyOpenSSL modules provide the ``OP_NO_SSLv2`` and + ``OP_NO_SSLv3`` flags for this purpose. + + + Config Options: + + .. code-block:: yaml + + ssl_with_bad_version: + bad_protocol_versions: + - PROTOCOL_SSLv2 + - SSLv2_METHOD + - SSLv23_METHOD + - PROTOCOL_SSLv3 # strict option + - PROTOCOL_TLSv1 # strict option + - SSLv3_METHOD # strict option + - TLSv1_METHOD # strict option + + + Sample Output: + + .. code-block:: none + + >> Issue: ssl.wrap_socket call with insecure SSL/TLS protocol version + identified, security issue. + Severity: High Confidence: High + Location: ./examples/ssl-insecure-version.py:13 + 12 # strict tests + 13 ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) + 14 ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) + + References: + + - http://heartbleed.com/ + - https://poodlebleed.com/ + - https://security.openstack.org/ + - https://security.openstack.org/guidelines/dg_move-data-securely.html + + .. versionadded:: 0.9.0 + """ bad_ssl_versions = get_bad_proto_versions(config) if (context.call_function_name_qual == 'ssl.wrap_socket'): if context.check_call_arg_value('ssl_version', bad_ssl_versions): @@ -58,6 +135,51 @@ def ssl_with_bad_version(context, config): @takes_config("ssl_with_bad_version") @checks('FunctionDef') def ssl_with_bad_defaults(context, config): + """Test for SSL use with bad defaults specified + + This plugin is part of a family of tests that detect the use of known bad + versions of SSL/TLS, please see :doc:`../plugins/ssl_with_bad_version` for + a complete discussion. Specifically, this plugin test scans for Python + methods with default parameter values that specify the use of broken + SSL/TLS protocol versions. Currently, detection supports methods using + Python's native SSL/TLS support and the pyOpenSSL module. A MEDIUM severity + warning will be reported whenever known broken protocol versions are + detected. + + See also: + + - :doc:`../plugins/ssl_with_bad_version` + - :doc:`../plugins/ssl_with_no_version` + + + Config Options: + + This test shares the configuration provided for the standard + :doc:`../plugins/ssl_with_bad_version` test, please refer to its + documentation. + + Sample Output: + + .. code-block:: none + + >> Issue: Function definition identified with insecure SSL/TLS protocol + version by default, possible security issue. + Severity: Medium Confidence: Medium + Location: ./examples/ssl-insecure-version.py:28 + 27 + 28 def open_ssl_socket(version=SSL.SSLv2_METHOD): + 29 pass + + References: + + - http://heartbleed.com/ + - https://poodlebleed.com/ + - https://security.openstack.org/ + - https://security.openstack.org/guidelines/dg_move-data-securely.html + + .. versionadded:: 0.9.0 + """ + bad_ssl_versions = get_bad_proto_versions(config) for default in context.function_def_defaults_qual: val = default.split(".")[-1] @@ -73,6 +195,51 @@ def ssl_with_bad_defaults(context, config): @checks('Call') def ssl_with_no_version(context): + """Test for SSL use with no version specified + + This plugin is part of a family of tests that detect the use of known bad + versions of SSL/TLS, please see :doc:`../plugins/ssl_with_bad_version` for + a complete discussion. Specifically, This plugin test scans for specific + methods in Python's native SSL/TLS support and the pyOpenSSL module that + configure the version of SSL/TLS protocol to use. These methods are known + to provide default value that maximize compatibility, but permit use of the + aforementioned broken protocol versions. A LOW severity warning will be + reported whenever this is detected. + + See also: + + - :doc:`../plugins/ssl_with_bad_version` + - :doc:`../plugins/ssl_with_bad_defaults` + + + Config Options: + + This test shares the configuration provided for the standard + :doc:`../plugins/ssl_with_bad_version` test, please refer to its + documentation. + + Sample Output: + + .. code-block:: none + + >> Issue: ssl.wrap_socket call with no SSL/TLS protocol version + specified, the default SSLv23 could be insecure, possible security + issue. + Severity: Low Confidence: Medium + Location: ./examples/ssl-insecure-version.py:23 + 22 + 23 ssl.wrap_socket() + 24 + + References: + + - http://heartbleed.com/ + - https://poodlebleed.com/ + - https://security.openstack.org/ + - https://security.openstack.org/guidelines/dg_move-data-securely.html + + .. versionadded:: 0.9.0 + """ if (context.call_function_name_qual == 'ssl.wrap_socket'): if context.check_call_arg_value('ssl_version') is None: # check_call_arg_value() returns False if the argument is found diff --git a/bandit/plugins/jinja2_templates.py b/bandit/plugins/jinja2_templates.py index 1e606f63..3e957d11 100644 --- a/bandit/plugins/jinja2_templates.py +++ b/bandit/plugins/jinja2_templates.py @@ -14,6 +14,64 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Jinja2 is a Python HTML templating system. It is typically used to build web +applications, though appears in other places well, notably the Ansible +automation system. When configuring the Jinja2 environment, the option to use +autoescaping on input can be specified. When autoescaping is enabled, Jinja2 +will filter input strings to escape any HTML content submitted via template +variables. Without escaping HTML input the application becomes vulnerable to +Cross Site Scripting (XSS) attacks. + +Unfortunately, autoescaping is False by default. Thus this plugin test will +warn on omission of an autoescape setting, as well as an explicit setting of +false. A HIGH severity warning is generated in either of these scenarios. + +Config Options +-------------- +None + + +Sample Output +------------- + +.. code-block:: none + + >> Issue: Using jinja2 templates with autoescape=False is dangerous and can + lead to XSS. Use autoescape=True to mitigate XSS vulnerabilities. + Severity: High Confidence: High + Location: ./examples/jinja2_templating.py:11 + 10 templateEnv = jinja2.Environment(autoescape=False, + loader=templateLoader) + 11 Environment(loader=templateLoader, + 12 load=templateLoader, + 13 autoescape=False) + 14 + + >> Issue: By default, jinja2 sets autoescape to False. Consider using + autoescape=True to mitigate XSS vulnerabilities. + Severity: High Confidence: High + Location: ./examples/jinja2_templating.py:15 + 14 + 15 Environment(loader=templateLoader, + 16 load=templateLoader) + 17 + + +References +---------- +- https://www.owasp.org/index.php/Cross-site_Scripting_(XSS) +- https://realpython.com/blog/python/primer-on-jinja-templating/ +- http://jinja.pocoo.org/docs/dev/api/#autoescaping +- https://security.openstack.org +- https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html + +.. versionadded:: 0.10.0 + +""" + import ast import bandit diff --git a/bandit/plugins/mako_templates.py b/bandit/plugins/mako_templates.py index f6816774..00f1ab07 100644 --- a/bandit/plugins/mako_templates.py +++ b/bandit/plugins/mako_templates.py @@ -12,6 +12,47 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Mako is a Python templating system often used to build web applications. It is +the default templating system used in Pylons and Pyramid. Unlike Jinja2 (an +alternative templating system), Mako has no environment wide variable escaping +mechanism. Because of this, all input variables must be carefully escaped +before use to prevent possible vulnerabilities to Cross Site Scripting (XSS) +attacks. + + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: Mako templates allow HTML/JS rendering by default and are + inherently open to XSS attacks. Ensure variables in all templates are + properly sanitized via the 'n', 'h' or 'x' flags (depending on context). + For example, to HTML escape the variable 'data' do ${ data |h }. + Severity: Medium Confidence: High + Location: ./examples/mako_templating.py:10 + 9 + 10 mako.template.Template("hern") + 11 template.Template("hern") + + +References +---------- +- http://www.makotemplates.org/ +- https://www.owasp.org/index.php/Cross-site_Scripting_(XSS) +- https://security.openstack.org +- https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html + +.. versionadded:: 0.10.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/bandit/plugins/secret_config_option.py b/bandit/plugins/secret_config_option.py index 9ff6c395..798c4836 100644 --- a/bandit/plugins/secret_config_option.py +++ b/bandit/plugins/secret_config_option.py @@ -12,6 +12,60 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Passwords are sensitive and must be protected appropriately. In OpenStack +Oslo there is an option to mark options "secret" which will ensure that they +are not logged. This plugin detects usages of oslo configuration functions +that appear to deal with strings ending in 'password' and flag usages where +they have not been marked secret. + +If such a value is found a MEDIUM severity error is generated. If 'False' or +'None' are explicitly set, Bandit will return a MEDIUM confidence issue. If +Bandit can't determine the value of secret it will return a LOW confidence +issue. + +Config Options +-------------- +.. code-block:: yaml + + password_config_option_not_marked_secret: + function_names: + - oslo.config.cfg.StrOpt + - oslo_config.cfg.StrOpt + +Sample Output +------------- +.. code-block:: none + + >> Issue: [password_config_option_not_marked_secret] oslo config option + possibly not marked secret=True identified. + Severity: Medium Confidence: Low + Location: examples/secret-config-option.py:12 + 11 help="User's password"), + 12 cfg.StrOpt('nova_password', + 13 secret=secret, + 14 help="Nova user password"), + 15 ] + + >> Issue: [password_config_option_not_marked_secret] oslo config option not + marked secret=True identifed, security issue. + Severity: Medium Confidence: Medium + Location: examples/secret-config-option.py:21 + 20 help="LDAP ubind ser name"), + 21 cfg.StrOpt('ldap_password', + 22 help="LDAP bind user password"), + 23 cfg.StrOpt('ldap_password_attribute', + +References +---------- +- https://security.openstack.org/guidelines/dg_protect-sensitive-data-in-files.html # noqa + +.. versionadded:: 0.10.0 + +""" + import bandit from bandit.core.test_properties import * from bandit.core import constants diff --git a/bandit/plugins/try_except_pass.py b/bandit/plugins/try_except_pass.py index 614cff36..a08bbb41 100644 --- a/bandit/plugins/try_except_pass.py +++ b/bandit/plugins/try_except_pass.py @@ -14,6 +14,70 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +Errors in Python code bases are typically communicated using ``Exceptions``. +An exception object is 'raised' in the event of an error and can be 'caught' at +a later point in the program, typically some error handling or logging action +will then be performed. + +However, it is possible to catch an exception and silently ignore it. This is +illustrated with the following example + +.. code-block:: python + + try: + do_some_stuff() + except Exception: + pass + +This pattern is considered bad practice in general, but also represents a +potential security issue. A larger than normal volume of errors from a service +can indicate an attempt is being made to disrupt or interfere with it. Thus +errors should, at the very least, be logged. + +There are rare situations where it is desirable to suppress errors, but this is +typically done with specific exception types, rather than the base Exception +class (or no type). To accommodate this, the test may be configured to ignore +'try, except, pass' where the exception is typed. For example, the following +would not generate a warning if the configuration option +``checked_typed_exception`` is set to False: + +.. code-block:: python + + try: + do_some_stuff() + except ZeroDivisionError: + pass + +Config Options +-------------- +.. code-block:: yaml + + try_except_pass: + check_typed_exception: True + + +Sample Output +------------- +.. code-block:: none + + >> Issue: Try, Except, Pass detected. + Severity: Low Confidence: High + Location: ./examples/try_except_pass.py:4 + 3 a = 1 + 4 except: + 5 pass + +References +---------- +- https://security.openstack.org + +.. versionadded:: 0.13.0 + +""" + import ast import bandit diff --git a/bandit/plugins/weak_cryptographic_key.py b/bandit/plugins/weak_cryptographic_key.py index fbf2e2c2..2e82d835 100644 --- a/bandit/plugins/weak_cryptographic_key.py +++ b/bandit/plugins/weak_cryptographic_key.py @@ -12,6 +12,40 @@ # License for the specific language governing permissions and limitations # under the License. +r""" +Description +----------- +As computational power increases, so does the ability to break ciphers with +smaller key lengths. The recommended key length size is 2048 and higher. 1024 +bits and below are now considered breakable. This plugin test checks for use +of any key less than 2048 bits and returns a high severity error if lower than +1024 and a medium severity error greater than 1024 but less than 2048. + +Config Options +-------------- +None + +Sample Output +------------- +.. code-block:: none + + >> Issue: DSA key sizes below 1024 bits are considered breakable. + Severity: High Confidence: High + Location: examples/weak_cryptographic_key_sizes.py:36 + 35 # Also incorrect: without keyword args + 36 dsa.generate_private_key(512, + 37 backends.default_backend()) + 38 rsa.generate_private_key(3, + +References +---------- + - http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf + - https://security.openstack.org/guidelines/dg_strong-crypto.html + +.. versionadded:: 0.14.0 + +""" + import bandit from bandit.core.test_properties import * diff --git a/docs/old/exec.md b/doc/old/exec.md similarity index 100% rename from docs/old/exec.md rename to doc/old/exec.md diff --git a/docs/old/jinja2.md b/doc/old/jinja2.md similarity index 100% rename from docs/old/jinja2.md rename to doc/old/jinja2.md diff --git a/docs/old/partial_paths.md b/doc/old/partial_paths.md similarity index 100% rename from docs/old/partial_paths.md rename to doc/old/partial_paths.md diff --git a/docs/old/ssl_tls.md b/doc/old/ssl_tls.md similarity index 100% rename from docs/old/ssl_tls.md rename to doc/old/ssl_tls.md diff --git a/docs/old/temp.md b/doc/old/temp.md similarity index 100% rename from docs/old/temp.md rename to doc/old/temp.md diff --git a/docs/old/xml.md b/doc/old/xml.md similarity index 100% rename from docs/old/xml.md rename to doc/old/xml.md diff --git a/docs/old/yaml.md b/doc/old/yaml.md similarity index 100% rename from docs/old/yaml.md rename to doc/old/yaml.md diff --git a/docs/source/conf.py b/doc/source/conf.py similarity index 100% rename from docs/source/conf.py rename to doc/source/conf.py diff --git a/docs/source/config.rst b/doc/source/config.rst similarity index 100% rename from docs/source/config.rst rename to doc/source/config.rst diff --git a/docs/source/formatters/index.rst b/doc/source/formatters/index.rst similarity index 100% rename from docs/source/formatters/index.rst rename to doc/source/formatters/index.rst diff --git a/docs/source/index.rst b/doc/source/index.rst similarity index 97% rename from docs/source/index.rst rename to doc/source/index.rst index 54301695..e1b3f86a 100644 --- a/docs/source/index.rst +++ b/doc/source/index.rst @@ -15,7 +15,7 @@ Getting Started :maxdepth: 1 config - tests/index + plugins/index formatters/index Indices and tables diff --git a/doc/source/plugins/any_other_function_with_shell_equals_true.rst b/doc/source/plugins/any_other_function_with_shell_equals_true.rst new file mode 100644 index 00000000..a4bcab3a --- /dev/null +++ b/doc/source/plugins/any_other_function_with_shell_equals_true.rst @@ -0,0 +1,8 @@ +----------------------------------------- +any_other_function_with_shell_equals_true +----------------------------------------- + +.. currentmodule:: bandit.plugins.injection_shell + +.. autofunction:: any_other_function_with_shell_equals_true + :noindex: diff --git a/doc/source/plugins/assert_used.rst b/doc/source/plugins/assert_used.rst new file mode 100644 index 00000000..5167d2fe --- /dev/null +++ b/doc/source/plugins/assert_used.rst @@ -0,0 +1,5 @@ +----------- +assert_used +----------- + +.. automodule:: bandit.plugins.asserts diff --git a/doc/source/plugins/blacklist_calls.rst b/doc/source/plugins/blacklist_calls.rst new file mode 100644 index 00000000..4c69869f --- /dev/null +++ b/doc/source/plugins/blacklist_calls.rst @@ -0,0 +1,5 @@ +--------------- +blacklist_calls +--------------- + +.. automodule:: bandit.plugins.blacklist_calls diff --git a/doc/source/plugins/blacklist_import_func.rst b/doc/source/plugins/blacklist_import_func.rst new file mode 100644 index 00000000..6efe10c0 --- /dev/null +++ b/doc/source/plugins/blacklist_import_func.rst @@ -0,0 +1,8 @@ +--------------------- +blacklist_import_func +--------------------- + +.. currentmodule:: bandit.plugins.blacklist_imports + +.. autofunction:: blacklist_import_func + :noindex: diff --git a/doc/source/plugins/blacklist_imports.rst b/doc/source/plugins/blacklist_imports.rst new file mode 100644 index 00000000..ea821201 --- /dev/null +++ b/doc/source/plugins/blacklist_imports.rst @@ -0,0 +1,8 @@ +----------------- +blacklist_imports +----------------- + +.. currentmodule:: bandit.plugins.blacklist_imports + +.. autofunction:: blacklist_imports + :noindex: diff --git a/doc/source/plugins/exec_used.rst b/doc/source/plugins/exec_used.rst new file mode 100644 index 00000000..31994a5a --- /dev/null +++ b/doc/source/plugins/exec_used.rst @@ -0,0 +1,5 @@ +--------- +exec_used +--------- + +.. automodule:: bandit.plugins.exec diff --git a/doc/source/plugins/execute_with_run_as_root_equals_true.rst b/doc/source/plugins/execute_with_run_as_root_equals_true.rst new file mode 100644 index 00000000..a2198899 --- /dev/null +++ b/doc/source/plugins/execute_with_run_as_root_equals_true.rst @@ -0,0 +1,5 @@ +------------------------------------ +execute_with_run_as_root_equals_true +------------------------------------ + +.. automodule:: bandit.plugins.exec_as_root diff --git a/doc/source/plugins/flask_debug_true.rst b/doc/source/plugins/flask_debug_true.rst new file mode 100644 index 00000000..06f472ad --- /dev/null +++ b/doc/source/plugins/flask_debug_true.rst @@ -0,0 +1,5 @@ +---------------- +flask_debug_true +---------------- + +.. automodule:: bandit.plugins.app_debug diff --git a/doc/source/plugins/hardcoded_bind_all_interfaces.rst b/doc/source/plugins/hardcoded_bind_all_interfaces.rst new file mode 100644 index 00000000..6011ea05 --- /dev/null +++ b/doc/source/plugins/hardcoded_bind_all_interfaces.rst @@ -0,0 +1,5 @@ +----------------------------- +hardcoded_bind_all_interfaces +----------------------------- + +.. automodule:: bandit.plugins.general_bind_all_interfaces diff --git a/doc/source/plugins/hardcoded_password.rst b/doc/source/plugins/hardcoded_password.rst new file mode 100644 index 00000000..b0259e75 --- /dev/null +++ b/doc/source/plugins/hardcoded_password.rst @@ -0,0 +1,5 @@ +------------------- +hardcoded_passwords +------------------- + +.. automodule:: bandit.plugins.general_hardcoded_password diff --git a/doc/source/plugins/hardcoded_sql_expressions.rst b/doc/source/plugins/hardcoded_sql_expressions.rst new file mode 100644 index 00000000..4196d644 --- /dev/null +++ b/doc/source/plugins/hardcoded_sql_expressions.rst @@ -0,0 +1,5 @@ +------------------------- +hardcoded_sql_expressions +------------------------- + +.. automodule:: bandit.plugins.injection_sql diff --git a/doc/source/plugins/hardcoded_tmp_directory.rst b/doc/source/plugins/hardcoded_tmp_directory.rst new file mode 100644 index 00000000..912eff51 --- /dev/null +++ b/doc/source/plugins/hardcoded_tmp_directory.rst @@ -0,0 +1,5 @@ +----------------------- +hardcoded_tmp_directory +----------------------- + +.. automodule:: bandit.plugins.general_hardcoded_tmp diff --git a/docs/source/tests/index.rst b/doc/source/plugins/index.rst similarity index 100% rename from docs/source/tests/index.rst rename to doc/source/plugins/index.rst diff --git a/doc/source/plugins/jinja2_autoescape_false.rst b/doc/source/plugins/jinja2_autoescape_false.rst new file mode 100644 index 00000000..1d77792f --- /dev/null +++ b/doc/source/plugins/jinja2_autoescape_false.rst @@ -0,0 +1,5 @@ +----------------------- +jinja2_autoescape_false +----------------------- + +.. automodule:: bandit.plugins.jinja2_templates diff --git a/doc/source/plugins/linux_commands_wildcard_injection.rst b/doc/source/plugins/linux_commands_wildcard_injection.rst new file mode 100644 index 00000000..5f65b1ef --- /dev/null +++ b/doc/source/plugins/linux_commands_wildcard_injection.rst @@ -0,0 +1,5 @@ +--------------------------------- +linux_commands_wildcard_injection +--------------------------------- + +.. automodule:: bandit.plugins.injection_wildcard diff --git a/doc/source/plugins/paramiko_calls.rst b/doc/source/plugins/paramiko_calls.rst new file mode 100644 index 00000000..e603889e --- /dev/null +++ b/doc/source/plugins/paramiko_calls.rst @@ -0,0 +1,5 @@ +-------------- +paramiko_calls +-------------- + +.. automodule:: bandit.plugins.injection_paramiko diff --git a/doc/source/plugins/password_config_option_not_marked_secret.rst b/doc/source/plugins/password_config_option_not_marked_secret.rst new file mode 100644 index 00000000..3c63c530 --- /dev/null +++ b/doc/source/plugins/password_config_option_not_marked_secret.rst @@ -0,0 +1,5 @@ +---------------------------------------- +password_config_option_not_marked_secret +---------------------------------------- + +.. automodule:: bandit.plugins.secret_config_option diff --git a/doc/source/plugins/request_with_no_cert_validation.rst b/doc/source/plugins/request_with_no_cert_validation.rst new file mode 100644 index 00000000..db84cefb --- /dev/null +++ b/doc/source/plugins/request_with_no_cert_validation.rst @@ -0,0 +1,5 @@ +------------------------------- +request_with_no_cert_validation +------------------------------- + +.. automodule:: bandit.plugins.crypto_request_no_cert_validation diff --git a/doc/source/plugins/set_bad_file_permissions.rst b/doc/source/plugins/set_bad_file_permissions.rst new file mode 100644 index 00000000..80212616 --- /dev/null +++ b/doc/source/plugins/set_bad_file_permissions.rst @@ -0,0 +1,5 @@ +------------------------ +set_bad_file_permissions +------------------------ + +.. automodule:: bandit.plugins.general_bad_file_permissions diff --git a/doc/source/plugins/ssl_with_bad_defaults.rst b/doc/source/plugins/ssl_with_bad_defaults.rst new file mode 100644 index 00000000..c188e11e --- /dev/null +++ b/doc/source/plugins/ssl_with_bad_defaults.rst @@ -0,0 +1,8 @@ +--------------------- +ssl_with_bad_defaults +--------------------- + +.. currentmodule:: bandit.plugins.insecure_ssl_tls + +.. autofunction:: ssl_with_bad_version + :noindex: diff --git a/doc/source/plugins/ssl_with_bad_version.rst b/doc/source/plugins/ssl_with_bad_version.rst new file mode 100644 index 00000000..0efe6669 --- /dev/null +++ b/doc/source/plugins/ssl_with_bad_version.rst @@ -0,0 +1,8 @@ +-------------------- +ssl_with_bad_version +-------------------- + +.. currentmodule:: bandit.plugins.insecure_ssl_tls + +.. autofunction:: ssl_with_bad_defaults + :noindex: diff --git a/doc/source/plugins/ssl_with_no_version.rst b/doc/source/plugins/ssl_with_no_version.rst new file mode 100644 index 00000000..a4ebbc58 --- /dev/null +++ b/doc/source/plugins/ssl_with_no_version.rst @@ -0,0 +1,8 @@ +------------------- +ssl_with_no_version +------------------- + +.. currentmodule:: bandit.plugins.insecure_ssl_tls + +.. autofunction:: ssl_with_no_version + :noindex: diff --git a/doc/source/plugins/start_process_with_a_shell.rst b/doc/source/plugins/start_process_with_a_shell.rst new file mode 100644 index 00000000..cfbe11c0 --- /dev/null +++ b/doc/source/plugins/start_process_with_a_shell.rst @@ -0,0 +1,8 @@ +-------------------------- +start_process_with_a_shell +-------------------------- + +.. currentmodule:: bandit.plugins.injection_shell + +.. autofunction:: start_process_with_a_shell + :noindex: diff --git a/doc/source/plugins/start_process_with_no_shell.rst b/doc/source/plugins/start_process_with_no_shell.rst new file mode 100644 index 00000000..86d41a08 --- /dev/null +++ b/doc/source/plugins/start_process_with_no_shell.rst @@ -0,0 +1,8 @@ +--------------------------- +start_process_with_no_shell +--------------------------- + +.. currentmodule:: bandit.plugins.injection_shell + +.. autofunction:: start_process_with_no_shell + :noindex: diff --git a/doc/source/plugins/start_process_with_partial_path.rst b/doc/source/plugins/start_process_with_partial_path.rst new file mode 100644 index 00000000..41ec62be --- /dev/null +++ b/doc/source/plugins/start_process_with_partial_path.rst @@ -0,0 +1,8 @@ +------------------------------- +start_process_with_partial_path +------------------------------- + +.. currentmodule:: bandit.plugins.injection_shell + +.. autofunction:: start_process_with_partial_path + :noindex: diff --git a/doc/source/plugins/subprocess_popen_with_shell_equals_true.rst b/doc/source/plugins/subprocess_popen_with_shell_equals_true.rst new file mode 100644 index 00000000..13d2c799 --- /dev/null +++ b/doc/source/plugins/subprocess_popen_with_shell_equals_true.rst @@ -0,0 +1,8 @@ +--------------------------------------- +subprocess_popen_with_shell_equals_true +--------------------------------------- + +.. currentmodule:: bandit.plugins.injection_shell + +.. autofunction:: subprocess_popen_with_shell_equals_true + :noindex: diff --git a/doc/source/plugins/subprocess_without_shell_equals_true.rst b/doc/source/plugins/subprocess_without_shell_equals_true.rst new file mode 100644 index 00000000..2dfc8046 --- /dev/null +++ b/doc/source/plugins/subprocess_without_shell_equals_true.rst @@ -0,0 +1,8 @@ +------------------------------------ +subprocess_without_shell_equals_true +------------------------------------ + +.. currentmodule:: bandit.plugins.injection_shell + +.. autofunction:: subprocess_without_shell_equals_true + :noindex: diff --git a/doc/source/plugins/try_except_pass.rst b/doc/source/plugins/try_except_pass.rst new file mode 100644 index 00000000..a895bab6 --- /dev/null +++ b/doc/source/plugins/try_except_pass.rst @@ -0,0 +1,5 @@ +--------------- +try_except_pass +--------------- + +.. automodule:: bandit.plugins.try_except_pass diff --git a/doc/source/plugins/use_of_mako_templates.rst b/doc/source/plugins/use_of_mako_templates.rst new file mode 100644 index 00000000..33641549 --- /dev/null +++ b/doc/source/plugins/use_of_mako_templates.rst @@ -0,0 +1,5 @@ +--------------------- +use_of_mako_templates +--------------------- + +.. automodule:: bandit.plugins.mako_templates diff --git a/doc/source/plugins/weak_cryptographic_key.rst b/doc/source/plugins/weak_cryptographic_key.rst new file mode 100644 index 00000000..44482967 --- /dev/null +++ b/doc/source/plugins/weak_cryptographic_key.rst @@ -0,0 +1,5 @@ +---------------------- +weak_cryptographic_key +---------------------- + +.. automodule:: bandit.plugins.weak_cryptographic_key diff --git a/docs/source/tests/any_other_function_with_shell_equals_true.rst b/docs/source/tests/any_other_function_with_shell_equals_true.rst deleted file mode 100644 index 90bddc93..00000000 --- a/docs/source/tests/any_other_function_with_shell_equals_true.rst +++ /dev/null @@ -1,65 +0,0 @@ -any_other_function_with_shell_equals_true -========================================= - -Description ------------ -Python possesses many mechanisms to invoke an external executable. However, -doing so may present a security issue if appropriate care is not taken to -sanitize any user provided or variable input. - -This plugin test is part of a family of tests built to check for process -spawning and warn appropriately. Specifically, this plugin test interrogates -method calls for the presence of a keyword parameter `shell` equalling true. It -is related to detection of shell injection issues and is intended to catch -custom wrappers to vulnerable methods that may have been created. - -See also: - -- :doc:`linux_commands_wildcard_injection`. -- :doc:`subprocess_popen_with_shell_equals_true`. -- :doc:`subprocess_without_shell_equals_true`. -- :doc:`start_process_with_no_shell`. -- :doc:`start_process_with_a_shell`. -- :doc:`start_process_with_partial_path`. - -Available Since ---------------- - - Bandit v 0.9.0 - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -Specifically, this plugin excludes those functions listed under the subprocess -section, these methods are tested in a separate specific test plugin and this -exclusion prevents duplicate issue reporting. - -.. code-block:: yaml - - shell_injection: - # Start a process using the subprocess module, or one of its wrappers. - subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, - subprocess.check_output, utils.execute, - utils.execute_with_timeout] - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Function call with shell=True parameter identified, possible - security issue. - Severity: Medium Confidence: High - Location: ./examples/subprocess_shell.py:9 - 8 pop('/bin/gcc --version', shell=True) - 9 Popen('/bin/gcc --version', shell=True) - 10 - -References ----------- - - https://security.openstack.org/guidelines/dg_avoid-shell-true.html - - https://security.openstack.org/guidelines/dg_use-subprocess-securely.html diff --git a/docs/source/tests/assert_used.rst b/docs/source/tests/assert_used.rst deleted file mode 100644 index 08faf7b0..00000000 --- a/docs/source/tests/assert_used.rst +++ /dev/null @@ -1,38 +0,0 @@ -assert_used -=========== - -Description ------------ -This plugin test checks for the use of the Python ``assert`` keyword. It was -discovered that some projects used assert to enforce interface constraints. -However, assert is removed with compiling to optimised byte code (python -o -producing \*.pyo files). This caused various protections to be removed. The use -of assert is also considered as general bad practice in OpenStack codebases. - -Please see https://docs.python.org/2/reference/simple_stmts.html#grammar-token-assert_stmt -for more info on ``assert`` - - -Available Since ---------------- - - Bandit v0.11.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. - Severity: Low Confidence: High - Location: ./examples/assert.py:1 - 1 assert logged_in - 2 display_assets() - -References ----------- - - https://bugs.launchpad.net/juniperopenstack/+bug/1456193 - - https://bugs.launchpad.net/heat/+bug/1397883 - - https://docs.python.org/2/reference/simple_stmts.html#grammar-token-assert_stmt diff --git a/docs/source/tests/blacklist_calls.rst b/docs/source/tests/blacklist_calls.rst deleted file mode 100644 index 96db71c9..00000000 --- a/docs/source/tests/blacklist_calls.rst +++ /dev/null @@ -1,71 +0,0 @@ - -blacklist_calls -=============== - -Description ------------ -A number of Python methods and functions are known to have potential security -implications. The blacklist calls plugin test is designed to detect the use of -these methods by scanning code for method calls and checking for their presence -in a configurable blacklist. The scanned calls are fully qualified and -de-aliased prior to checking. To illustrate this, imagine a check for -"evil.thing()" running on the following example code: - -.. code-block:: python - - import evil as good - - good.thing() - thing() - -This would generate a warning about calling `evil.thing()` despite the module -being aliased as `good`. It would also not generate a warning on the call to -`thing()` in the local module, as it's fully qualified name will not match. - -Each of the provided blacklisted calls can be grouped such that they generate -appropriate warnings (message, severity) and a token `{func}` may be used -in the provided output message, to be replaced with the actual method name. - -Due to the nature of the test, confidence is always reported as HIGH - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -.. code-block:: yaml - - blacklist_calls: - bad_name_sets: - - pickle: - qualnames: - - pickle.loads - - pickle.load - - pickle.Unpickler - - cPickle.loads - - cPickle.load - - cPickle.Unpickler - message: > - Pickle library appears to be in use, possible security issue. - - marshal: - qualnames: [marshal.load, marshal.loads] - message: > - Deserialization with the {func} is possibly dangerous. - level: LOW - -Sample Output -------------- -.. code-block:: none - - >> Issue: Pickle library appears to be in use, possible security issue. - - Severity: Medium Confidence: High - Location: ./examples/pickle_deserialize.py:20 - 19 serialized = cPickle.dumps({(): []}) - 20 print(cPickle.loads(serialized)) - 21 - -References ----------- -- https://security.openstack.org diff --git a/docs/source/tests/blacklist_import_func.rst b/docs/source/tests/blacklist_import_func.rst deleted file mode 100644 index 8c141fd7..00000000 --- a/docs/source/tests/blacklist_import_func.rst +++ /dev/null @@ -1,55 +0,0 @@ - -blacklist_import_func -===================== -Description ------------ -This test is in all ways identical to :doc:`blacklist_imports`. However, it -is designed to catch modules that have been imported using Python's special -builtin import function, `__import__()`. For example, running a test on the -following code for `module.evil` would warn as shown: - -.. code-block:: python - - __import__('module') # no warning - __import__('module.evil') # warning - -Please see the documentation for :doc:`blacklist_imports` for more details. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This test shares the configuration provided for the standard -:doc:`blacklist_imports` test. - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Using xml.sax to parse untrusted XML data is known to be - vulnerable to XML attacks. Replace xml.sax with the equivalent defusedxml - package. - - Severity: Low Confidence: High - Location: ./examples/xml_sax.py:1 - 1 import xml.sax - 2 from xml import sax - - >> Issue: Using xml.sax.parseString to parse untrusted XML data is known to - be vulnerable to XML attacks. Replace xml.sax.parseString with its - defusedxml equivalent function. - - Severity: Medium Confidence: High - Location: ./examples/xml_sax.py:21 - 20 # bad - 21 xml.sax.parseString(xmlString, ExampleContentHandler()) - 22 xml.sax.parse('notaxmlfilethatexists.xml', ExampleContentHandler()) - - -References ----------- -- :doc:`blacklist_imports`. -- https://security.openstack.org diff --git a/docs/source/tests/blacklist_imports.rst b/docs/source/tests/blacklist_imports.rst deleted file mode 100644 index 3d7fa270..00000000 --- a/docs/source/tests/blacklist_imports.rst +++ /dev/null @@ -1,87 +0,0 @@ - -blacklist_imports -================= - -Description ------------ -A number of Python modules are known to provide collections of functionality -with potential security implications. The blacklist imports plugin test is -designed to detect the use of these modules by scanning code for `import` -statements and checking for the imported modules presence in a configurable -blacklist. The imported modules are fully qualified and de-aliased prior to -checking. To illustrate this, imagine a check for "module.evil" running on the -following example code: - -.. code-block:: python - - import module # no warning - import module.evil # warning - from module import evil # warning - from module import evil as good # warning - -This would generate a warning about importing `module.evil` in each of the last -three cases, despite the module being aliased as `good` in one of them. It would -also not generate a warning on the first import (of `module`) as it's fully -qualified name will not match. - -Each of the provided blacklisted modules can be grouped such that they generate -appropriate warnings (message, severity) and a token `{module}` may be used -in the provided output message, to be replaced with the actual module name. - -Due to the nature of the test, confidence is always reported as HIGH - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -.. code-block:: yaml - - blacklist_imports: - bad_import_sets: - - xml_libs: - imports: - - xml.etree.cElementTree - - xml.etree.ElementTree - - xml.sax.expatreader - - xml.sax - - xml.dom.expatbuilder - - xml.dom.minidom - - xml.dom.pulldom - - lxml.etree - - lxml - message: > - Using {module} to parse untrusted XML data is known to be - vulnerable to XML attacks. Replace {module} with the - equivalent defusedxml package. - level: LOW - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Using xml.sax to parse untrusted XML data is known to be - vulnerable to XML attacks. Replace xml.sax with the equivalent defusedxml - package. - - Severity: Low Confidence: High - Location: ./examples/xml_sax.py:1 - 1 import xml.sax - 2 from xml import sax - - >> Issue: Using xml.sax.parseString to parse untrusted XML data is known to - be vulnerable to XML attacks. Replace xml.sax.parseString with its - defusedxml equivalent function. - - Severity: Medium Confidence: High - Location: ./examples/xml_sax.py:21 - 20 # bad - 21 xml.sax.parseString(xmlString, ExampleContentHandler()) - 22 xml.sax.parse('notaxmlfilethatexists.xml', ExampleContentHandler()) - -References ----------- -- see also :doc:`blacklist_import_func`. -- https://security.openstack.org diff --git a/docs/source/tests/exec_used.rst b/docs/source/tests/exec_used.rst deleted file mode 100644 index 10d8bcbe..00000000 --- a/docs/source/tests/exec_used.rst +++ /dev/null @@ -1,32 +0,0 @@ -exec_used -========= - -Description ------------ -This plugin test checks for the use of Python's `exec` method or keyword. The -Python docs succinctly describe why the use of `exec` is risky: - - - `This statement supports dynamic execution of Python code.` [1]_ - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: Use of exec detected. - Severity: Medium Confidence: High - Location: ./examples/exec-py2.py:2 - 1 exec("do evil") - 2 exec "do evil" - -References ----------- -.. [1] https://docs.python.org/2.0/ref/exec.html -.. [2] TODO : add info on exec and similar to sec best practice and link here diff --git a/docs/source/tests/execute_with_run_as_root_equals_true.rst b/docs/source/tests/execute_with_run_as_root_equals_true.rst deleted file mode 100644 index dde5cc94..00000000 --- a/docs/source/tests/execute_with_run_as_root_equals_true.rst +++ /dev/null @@ -1,51 +0,0 @@ - -execute_with_run_as_root_equals_true -==================================== - -Description ------------ -Running commands as root dramatically increase their potential risk. Running -commands with restricted user privileges provides defense in depth against -command injection attacks, or developer and configuration error. This plugin -test checks for specific methods being called with a keyword parameter -`run_as_root` set to True, a common OpenStack idiom. - - -Available Since ---------------- - - Bandit v0.10.0 - -Config Options --------------- -This test plugin takes a similarly named configuration block, -`execute_with_run_as_root_equals_true`, providing a list, `function_names`, of -function names. A call to any of these named functions will be checked for a -`run_as_root` keyword parameter, and if True, will report a Low severity -issue. - -.. code-block:: yaml - - execute_with_run_as_root_equals_true: - function_names: - - ceilometer.utils.execute - - cinder.utils.execute - - neutron.agent.linux.utils.execute - - nova.utils.execute - - nova.utils.trycmd - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Execute with run_as_root=True identified, possible security issue. - Severity: Low Confidence: Medium - Location: ./examples/exec-as-root.py:26 - 25 nova_utils.trycmd('gcc --version') - 26 nova_utils.trycmd('gcc --version', run_as_root=True) - 27 - -References ----------- - - https://security.openstack.org/guidelines/dg_rootwrap-recommendations-and-plans.html - - https://security.openstack.org/guidelines/dg_use-oslo-rootwrap-securely.html diff --git a/docs/source/tests/flask_debug_true.rst b/docs/source/tests/flask_debug_true.rst deleted file mode 100644 index 43a912c8..00000000 --- a/docs/source/tests/flask_debug_true.rst +++ /dev/null @@ -1,39 +0,0 @@ - -flask_debug_true -================ - -Description ------------ -Running Flask applications in debug mode results in the Werkzeug debugger -being enabled. This includes a feature that allows arbitrary code execution. -Documentation for both Flask [1]_ and Werkzeug [2]_ strongly suggests that -debug mode should never be enabled on production systems. - -Operating a production server with debug mode enabled was the probable cause -of the Patreon breach in 2015 [3]_. - -Available Since ---------------- - - Bandit v0.15.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: A Flask app appears to be run with debug=True, which exposes - the Werkzeug debugger and allows the execution of arbitrary code. - Severity: High Confidence: High - Location: examples/flask_debug.py:10 - 9 #bad - 10 app.run(debug=True) - 11 - -References ----------- -.. [1] http://flask.pocoo.org/docs/0.10/quickstart/#debug-mode -.. [2] http://werkzeug.pocoo.org/docs/0.10/debug/ -.. [3] http://labs.detectify.com/post/130332638391/how-patreon-got-hacked-publicly-exposed-werkzeug diff --git a/docs/source/tests/hardcoded_bind_all_interfaces.rst b/docs/source/tests/hardcoded_bind_all_interfaces.rst deleted file mode 100644 index 7224dee8..00000000 --- a/docs/source/tests/hardcoded_bind_all_interfaces.rst +++ /dev/null @@ -1,33 +0,0 @@ - -hardcoded_bind_all_interfaces -============================= - -Description ------------ -Binding to all network interfaces can potentially open up a service to traffic -on unintended interfaces, that may not be properly documented or secured. This -plugin test looks for a string pattern "0.0.0.0" that may indicate a hardcoded -binding to all network interfaces. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: Possible binding to all interfaces. - Severity: Medium Confidence: Medium - Location: ./examples/binding.py:4 - 3 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - 4 s.bind(('0.0.0.0', 31137)) - 5 s.bind(('192.168.0.1', 8080)) - -References ----------- - - __TODO__ : add best practice info on binding to all interfaces, and link here. diff --git a/docs/source/tests/hardcoded_password.rst b/docs/source/tests/hardcoded_password.rst deleted file mode 100644 index 571dc572..00000000 --- a/docs/source/tests/hardcoded_password.rst +++ /dev/null @@ -1,45 +0,0 @@ - -hardcoded_password -================== - -Description ------------ -The use of hard-coded passwords increases the possibility of password guessing -tremendously. This plugin test looks for all string literals and checks to see -if they exist in a list of likely default passwords. If they are found in the -list, a LOW severity issue is reported. - -Note: this test is very noisy and likely to result in many false positives. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This plugin test takes a similarly named config block, `hardcoded_password`. -Here a path, `word_list`, can be given to indicate where the default password -word list file may be found. - -.. code-block:: yaml - - hardcoded_password: - # Support for full path, relative path and special "%(site_data_dir)s" - # substitution (/usr/{local}/share) - word_list: "%(site_data_dir)s/wordlist/default-passwords" - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Possible hardcoded password '(root)' - Severity: Low Confidence: Low - Location: ./examples/hardcoded-passwords.py:5 - 4 def someFunction2(password): - 5 if password == "root": - 6 print("OK, logged in") - -References ----------- -- https://www.owasp.org/index.php/Use_of_hard-coded_password diff --git a/docs/source/tests/hardcoded_sql_expressions.rst b/docs/source/tests/hardcoded_sql_expressions.rst deleted file mode 100644 index 9fad036a..00000000 --- a/docs/source/tests/hardcoded_sql_expressions.rst +++ /dev/null @@ -1,48 +0,0 @@ -hardcoded_sql_expressions -========================= - -Description ------------ -An SQL injection attack consists of insertion or "injection" of a SQL query via -the input data given to an application. It is a very common attack vector. This -plugin test looks for strings that resemble SQL statements that are involved in -some form of string building operation. For example: - - - "SELECT %s FROM derp;" % var - - "SELECT thing FROM " + tab - - "SELECT " + val + " FROM " + tab + ... - -Unless care is taken to sanitize and control the input data when building such -SQL statement strings, an injection attack becomes possible. If strings of this -nature are discovered, a LOW confidence issue is reported. In order to boost -result confidence, this plugin test will also check to see if the discovered -string is in use with standard Python DBAPI calls `execute` or `executemany`. -If so, a MEDIUM issue is reported. For example: - - - cursor.execute("SELECT %s FROM derp;" % var) - - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -None - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Possible SQL injection vector through string-based query construction. - Severity: Medium Confidence: Low - Location: ./examples/sql_statements_without_sql_alchemy.py:4 - 3 query = "DELETE FROM foo WHERE id = '%s'" % identifier - 4 query = "UPDATE foo SET value = 'b' WHERE id = '%s'" % identifier - 5 - -References ----------- -- https://www.owasp.org/index.php/SQL_Injection -- https://security.openstack.org/guidelines/dg_parameterize-database-queries.html diff --git a/docs/source/tests/hardcoded_tmp_directory.rst b/docs/source/tests/hardcoded_tmp_directory.rst deleted file mode 100644 index fb2ff8e7..00000000 --- a/docs/source/tests/hardcoded_tmp_directory.rst +++ /dev/null @@ -1,45 +0,0 @@ - -hardcoded_tmp_directory -======================= - -Description ------------ -Safely creating a temporary file or directory means following a number of rules -(see the references for more details). This plugin test looks for strings -starting with (configurable) commonly used temporary paths, for example: - - - /tmp - - /var/tmp - - /dev/shm - - etc - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This test plugin takes a similarly named config block, `hardcoded_tmp_directory`. -The config block provides a Python list, `tmp_dirs`, that lists string fragments -indicating possible temporary file paths. Any string starting with one of these -fragments will report a MEDIUM confidence issue. - -.. code-block:: yaml - - hardcoded_tmp_directory: - tmp_dirs: ['/tmp', '/var/tmp', '/dev/shm'] - - -Sample Output -------------- -.. code-block: none - - >> Issue: Probable insecure usage of temp file/directory. - Severity: Medium Confidence: Medium - Location: ./examples/hardcoded-tmp.py:1 - 1 f = open('/tmp/abc', 'w') - 2 f.write('def') - -References ----------- - - https://security.openstack.org/guidelines/dg_using-temporary-files-securely.html diff --git a/docs/source/tests/jinja2_autoescape_false.rst b/docs/source/tests/jinja2_autoescape_false.rst deleted file mode 100644 index 97a28ac0..00000000 --- a/docs/source/tests/jinja2_autoescape_false.rst +++ /dev/null @@ -1,59 +0,0 @@ - -jinja2_autoescape_false -======================= - -Description ------------ -Jinja2 is a Python HTML templating system. It is typically used to build web -applications, though appears in other places well, notably the Ansible -automation system. When configuring the Jinja2 environment, the option to use -autoescaping on input can be specified. When autoescaping is enabled, Jinja2 -will filter input strings to escape any HTML content submitted via template -variables. Without escaping HTML input the application becomes vulnerable to -Cross Site Scripting (XSS) attacks. - -Unfortunately, autoescaping is False by default. Thus this plugin test will warn -on omission of an autoescape setting, as well as an explicit setting of false. A -HIGH severity warning is generated in either of these scenarios. - -Available Since ---------------- - - Bandit v0.10.0 - -Config Options --------------- -None - - -Sample Output -------------- - -.. code-block:: none - - >> Issue: Using jinja2 templates with autoescape=False is dangerous and can - lead to XSS. Use autoescape=True to mitigate XSS vulnerabilities. - Severity: High Confidence: High - Location: ./examples/jinja2_templating.py:11 - 10 templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) - 11 Environment(loader=templateLoader, - 12 load=templateLoader, - 13 autoescape=False) - 14 - - >> Issue: By default, jinja2 sets autoescape to False. Consider using - autoescape=True to mitigate XSS vulnerabilities. - Severity: High Confidence: High - Location: ./examples/jinja2_templating.py:15 - 14 - 15 Environment(loader=templateLoader, - 16 load=templateLoader) - 17 - - -References ----------- -- https://www.owasp.org/index.php/Cross-site_Scripting_(XSS) -- https://realpython.com/blog/python/primer-on-jinja-templating/ -- http://jinja.pocoo.org/docs/dev/api/#autoescaping -- https://security.openstack.org -- https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html diff --git a/docs/source/tests/linux_commands_wildcard_injection.rst b/docs/source/tests/linux_commands_wildcard_injection.rst deleted file mode 100644 index 9fc62cb2..00000000 --- a/docs/source/tests/linux_commands_wildcard_injection.rst +++ /dev/null @@ -1,98 +0,0 @@ - -linux_commands_wildcard_injection -================================= - -Description ------------ -Python provides a number of methods that emulate the behavior of standard Linux -command line utilities. Like their Linux counterparts, these commands may take -a wildcard "\*" character in place of a file system path. This is interpreted -to mean "any and all files or folders" and can be used to build partially -qualified paths, such as "/home/user/\*". - -The use of partially qualified paths may result in unintended consequences if -an unexpected file or symlink is placed into the path location given. This -becomes particularly dangerous when combined with commands used to manipulate -file permissions or copy data off of a system. - -This test plugin looks for usage of the following commands in conjunction with -wild card parameters: - -- 'chown' -- 'chmod' -- 'tar' -- 'rsync' - -As well as any method configured in the shell or subprocess injection test -configurations. See also :doc:`start_process_with_partial_path` for related -issues with partial paths. - - -Available Since ---------------- - - Bandit v0.9.0 - - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -This test will scan parameters of all methods in all sections. Note that methods -are fully qualified and de-aliased prior to checking. - -see also: - -- :doc:`start_process_with_partial_path` -- :doc:`start_process_with_a_shell` -- :doc:`start_process_with_no_shell` - -.. code-block:: yaml - - shell_injection: - # Start a process using the subprocess module, or one of its wrappers. - subprocess: - - subprocess.Popen - - subprocess.call - - # Start a process with a function vulnerable to shell injection. - shell: - - os.system - - os.popen - - popen2.Popen3 - - popen2.Popen4 - - commands.getoutput - - commands.getstatusoutput - # Start a process with a function that is not vulnerable to shell injection. - no_shell: - - os.execl - - os.execle - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Possible wildcard injection in call: subprocess.Popen - Severity: High Confidence: Medium - Location: ./examples/wildcard-injection.py:8 - 7 o.popen2('/bin/chmod *') - 8 subp.Popen('/bin/chown *', shell=True) - 9 - - >> Issue: subprocess call - check for execution of untrusted input. - Severity: Low Confidence: High - Location: ./examples/wildcard-injection.py:11 - 10 # Not vulnerable to wildcard injection - 11 subp.Popen('/bin/rsync *') - 12 subp.Popen("/bin/chmod *") - - -References ----------- -- https://security.openstack.org -- https://en.wikipedia.org/wiki/Wildcard_character -- http://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt diff --git a/docs/source/tests/paramiko_calls.rst b/docs/source/tests/paramiko_calls.rst deleted file mode 100644 index 2c91be22..00000000 --- a/docs/source/tests/paramiko_calls.rst +++ /dev/null @@ -1,52 +0,0 @@ - -paramiko_calls -============== - -Description ------------ -Paramiko is a Python library designed to work with the SSH2 protocol for secure -(encrypted and authenticated) connections to remote machines. It is intended to -run commands on a remote host. These commands are run within a shell on the -target and are thus vulnerable to various shell injection attacks. Bandit -reports a MEDIUM issue when it detects the use of Paramiko's "exec_command" or -"invoke_shell" methods advising the user to check inputs are correctly -sanitized. - -See also: - -- :doc:`start_process_with_a_shell` -- :doc:`subprocess_popen_with_shell_equals_true` - - -Available Since ---------------- - - Bandit v0.12.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: Possible shell injection via Paramiko call, check inputs are properly sanitized. - Severity: Medium Confidence: Medium - Location: ./examples/paramiko_injection.py:4 - 3 # this is not safe - 4 paramiko.exec_command('something; reallly; unsafe') - 5 - - >> Issue: Possible shell injection via Paramiko call, check inputs are properly sanitized. - Severity: Medium Confidence: Medium - Location: ./examples/paramiko_injection.py:10 - 9 # this is not safe - 10 SSHClient.invoke_shell('something; bad; here\n') - 11 - -References ----------- - -- https://security.openstack.org -- https://github.com/paramiko/paramiko -- https://www.owasp.org/index.php/Command_Injection diff --git a/docs/source/tests/password_config_option_not_marked_secret.rst b/docs/source/tests/password_config_option_not_marked_secret.rst deleted file mode 100644 index 9148bc90..00000000 --- a/docs/source/tests/password_config_option_not_marked_secret.rst +++ /dev/null @@ -1,57 +0,0 @@ - -password_config_option_not_marked_secret -======================================== - -Description ------------ -Passwords are sensitive and must be protected appropriately. In OpenStack -Oslo there is an option to mark options "secret" which will ensure that they -are not logged. This plugin detects usages of oslo configuration functions -that appear to deal with strings ending in 'password' and flag usages where -they have not been marked secret. - -If such a value is found a MEDIUM severity error is generated. If 'False' or -'None' are explicitly set, Bandit will return a MEDIUM confidence issue. If -Bandit can't determine the value of secret it will return a LOW confidence -issue. - -Available Since ---------------- - - Bandit v0.10.0 - -Config Options --------------- -.. code-block:: yaml - - password_config_option_not_marked_secret: - function_names: - - oslo.config.cfg.StrOpt - - oslo_config.cfg.StrOpt - -Sample Output -------------- -.. code-block:: none - - >> Issue: [password_config_option_not_marked_secret] oslo config option - possibly not marked secret=True identified. - Severity: Medium Confidence: Low - Location: examples/secret-config-option.py:12 - 11 help="User's password"), - 12 cfg.StrOpt('nova_password', - 13 secret=secret, - 14 help="Nova user password"), - 15 ] - - >> Issue: [password_config_option_not_marked_secret] oslo config option not - marked secret=True identifed, security issue. - Severity: Medium Confidence: Medium - Location: examples/secret-config-option.py:21 - 20 help="LDAP ubind ser name"), - 21 cfg.StrOpt('ldap_password', - 22 help="LDAP bind user password"), - 23 cfg.StrOpt('ldap_password_attribute', - -References ----------- -- https://security.openstack.org/guidelines/dg_protect-sensitive-data-in-files.html -- http://docs.openstack.org/developer/oslo.config/cfg.html#special-handling-instructions diff --git a/docs/source/tests/request_with_no_cert_validation.rst b/docs/source/tests/request_with_no_cert_validation.rst deleted file mode 100644 index 3736c7b5..00000000 --- a/docs/source/tests/request_with_no_cert_validation.rst +++ /dev/null @@ -1,40 +0,0 @@ - -request_with_no_cert_validation -=============================== - -Description ------------ -Encryption in general is typically critical to the security of many -applications. Using TLS can greatly increase security by guaranteeing the -identity of the party you are communicating with. This is accomplished by one -or both parties presenting trusted certificates during the connection -initialization phase of TLS. - -When request methods are used certificates are validated automatically which is -the desired behavior. If certificate validation is explicitly turned off -Bandit will return a HIGH severity error. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: [request_with_no_cert_validation] Requests call with verify=False - disabling SSL certificate checks, security issue. - Severity: High Confidence: High - Location: examples/requests-ssl-verify-disabled.py:4 - 3 requests.get('https://gmail.com', verify=True) - 4 requests.get('https://gmail.com', verify=False) - 5 requests.post('https://gmail.com', verify=True) - -References ----------- -- https://security.openstack.org/guidelines/dg_move-data-securely.html -- https://security.openstack.org/guidelines/dg_validate-certificates.html diff --git a/docs/source/tests/set_bad_file_permissions.rst b/docs/source/tests/set_bad_file_permissions.rst deleted file mode 100644 index 8147e0ed..00000000 --- a/docs/source/tests/set_bad_file_permissions.rst +++ /dev/null @@ -1,47 +0,0 @@ - -set_bad_file_permissions -======================== - -Description ------------ -POSIX based operating systems utilize a permissions model to protect access to -parts of the file system. This model supports three roles "owner", "group" -and "world" each role may have a combination of "read", "write" or "execute" -flags sets. Python provides ``chmod`` to manipulate POSIX style permissions. - -This plugin test looks for the use of ``chmod`` and will alert when it is used -to set particularly permissive control flags. A MEDIUM warning is generated if -a file is set to group executable and a HIGH warning is reported if a file is -set world writable. Warnings are given with HIGH confidence. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: Probable insecure usage of temp file/directory. - Severity: Medium Confidence: Medium - Location: ./examples/os-chmod-py2.py:15 - 14 os.chmod('/etc/hosts', 0o777) - 15 os.chmod('/tmp/oh_hai', 0x1ff) - 16 os.chmod('/etc/passwd', stat.S_IRWXU) - - >> Issue: Chmod setting a permissive mask 0777 on file (key_file). - Severity: High Confidence: High - Location: ./examples/os-chmod-py2.py:17 - 16 os.chmod('/etc/passwd', stat.S_IRWXU) - 17 os.chmod(key_file, 0o777) - 18 - -References ----------- -- https://security.openstack.org/guidelines/dg_apply-restrictive-file-permissions.html -- https://en.wikipedia.org/wiki/File_system_permissions -- https://security.openstack.org diff --git a/docs/source/tests/ssl_with_bad_defaults.rst b/docs/source/tests/ssl_with_bad_defaults.rst deleted file mode 100644 index 580fc52d..00000000 --- a/docs/source/tests/ssl_with_bad_defaults.rst +++ /dev/null @@ -1,57 +0,0 @@ - -ssl_with_bad_defaults -===================== - -Description ------------ -Several highly publicized [1]_ [2]_, exploitable flaws have been discovered in -all versions of SSL and early versions of TLS. It is strongly recommended that -use of the following known broken protocol versions be avoided: - -- SSL v2 -- SSL v3 -- TLS v1 -- TLS v1.1 - -This plugin is part of a family of tests that detect the use of known bad -versions of SSL/TLS, please see :doc:`ssl_with_bad_version` for a complete -discussion. Specifically, this plugin test scans for Python methods with default -parameter values that specify the use of broken SSL/TLS protocol versions. -Currently, detection supports methods using Python's native SSL/TLS support and -the pyOpenSSL module. A MEDIUM severity warning will be reported whenever known -broken protocol versions are detected. - -See also: - -- :doc:`ssl_with_bad_version`. -- :doc:`ssl_with_no_version`. - - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This test shares the configuration provided for the standard -:doc:`ssl_with_bad_version` test, please refer to it's -:ref:`bad_ssl_config_options` documentation. - -Sample Output -------------- -.. code-block:: none - - >> Issue: Function definition identified with insecure SSL/TLS protocol - version by default, possible security issue. - Severity: Medium Confidence: Medium - Location: ./examples/ssl-insecure-version.py:28 - 27 - 28 def open_ssl_socket(version=SSL.SSLv2_METHOD): - 29 pass - -References ----------- -- [1] http://heartbleed.com/ -- [2] https://poodlebleed.com/ -- https://security.openstack.org/ -- https://security.openstack.org/guidelines/dg_move-data-securely.html diff --git a/docs/source/tests/ssl_with_bad_version.rst b/docs/source/tests/ssl_with_bad_version.rst deleted file mode 100644 index 6a7a2e76..00000000 --- a/docs/source/tests/ssl_with_bad_version.rst +++ /dev/null @@ -1,83 +0,0 @@ - -ssl_with_bad_version -==================== - -Description ------------ -Several highly publicized [1]_ [2]_, exploitable flaws have been discovered in -all versions of SSL and early versions of TLS. It is strongly recommended that -use of the following known broken protocol versions be avoided: - -- SSL v2 -- SSL v3 -- TLS v1 -- TLS v1.1 - -This plugin test scans for calls to Python methods with parameters that indicate -the used broken SSL/TLS protocol versions. Currently, detection supports methods -using Python's native SSL/TLS support and the pyOpenSSL module. A HIGH severity -warning will be reported whenever known broken protocol versions are detected. - -It is worth noting that native support for TLS 1.2 is only available in more -recent Python versions, specifically 2.7.9 and up, and 3.x - -See also: - -- :doc:`ssl_with_bad_defaults`. -- :doc:`ssl_with_no_version`. - -A note on 'SSLv23' ------------------- -Amongst the available SSL/TLS versions provided by Python/pyOpenSSL there exists -the option to use SSLv23. This very poorly named option actually means "use the -highest version of SSL/TLS supported by both the server and client". This may -(and should be) a version well in advance of SSL v2 or v3. Bandit can scan for -the use of SSLv23 if desired, but its detection does not necessarily indicate a -problem. - -When using SSLv23 it is important to also provide flags to explicitly exclude -bad versions of SSL/TLS from the protocol versions considered. Both the Python -native and pyOpenSSL modules provide the ``OP_NO_SSLv2`` and ``OP_NO_SSLv3`` -flags for this purpose. - - -Available Since ---------------- - - Bandit v0.9.0 - - .. _bad_ssl_config_options: - -Config Options --------------- -.. code-block:: yaml - - ssl_with_bad_version: - bad_protocol_versions: - - PROTOCOL_SSLv2 - - SSLv2_METHOD - - SSLv23_METHOD - - PROTOCOL_SSLv3 # strict option - - PROTOCOL_TLSv1 # strict option - - SSLv3_METHOD # strict option - - TLSv1_METHOD # strict option - - -Sample Output -------------- -.. code-block:: none - - >> Issue: ssl.wrap_socket call with insecure SSL/TLS protocol version - identified, security issue. - Severity: High Confidence: High - Location: ./examples/ssl-insecure-version.py:13 - 12 # strict tests - 13 ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) - 14 ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) - -References ----------- -- [1] http://heartbleed.com/ -- [2] https://poodlebleed.com/ -- https://security.openstack.org/ -- https://security.openstack.org/guidelines/dg_move-data-securely.html - diff --git a/docs/source/tests/ssl_with_no_version.rst b/docs/source/tests/ssl_with_no_version.rst deleted file mode 100644 index 8b5db223..00000000 --- a/docs/source/tests/ssl_with_no_version.rst +++ /dev/null @@ -1,59 +0,0 @@ - -ssl_with_no_version -=================== - -Description ------------ -Several highly publicized [1]_ [2]_, exploitable flaws have been discovered in -all versions of SSL and early versions of TLS. It is strongly recommended that -use of the following known broken protocol versions be avoided: - -- SSL v2 -- SSL v3 -- TLS v1 -- TLS v1.1 - -This plugin is part of a family of tests that detect the use of known bad -versions of SSL/TLS, please see :doc:`ssl_with_bad_version` for a complete -discussion. Specifically, This plugin test scans for specific methods in -Python's native SSL/TLS support and the pyOpenSSL module that configure the -version of SSL/TLS protocol to use. These methods are known to provide default -value that maximize compatibility, but permit use of the aforementioned broken -protocol versions. A LOW severity warning will be reported whenever this is -detected. - -See also: - -- :doc:`ssl_with_bad_version`. -- :doc:`ssl_with_bad_defaults`. - - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This test shares the configuration provided for the standard -:doc:`ssl_with_bad_version` test, please refer to it's -:ref:`bad_ssl_config_options` documentation. - -Sample Output -------------- -.. code-block:: none - - >> Issue: ssl.wrap_socket call with no SSL/TLS protocol version specified, - the default SSLv23 could be insecure, possible security issue. - Severity: Low Confidence: Medium - Location: ./examples/ssl-insecure-version.py:23 - 22 - 23 ssl.wrap_socket() - 24 - -References ----------- -- [1] http://heartbleed.com/ -- [2] https://poodlebleed.com/ -- https://security.openstack.org/ -- https://security.openstack.org/guidelines/dg_move-data-securely.html - diff --git a/docs/source/tests/start_process_with_a_shell.rst b/docs/source/tests/start_process_with_a_shell.rst deleted file mode 100644 index c435c9de..00000000 --- a/docs/source/tests/start_process_with_a_shell.rst +++ /dev/null @@ -1,73 +0,0 @@ - -start_process_with_a_shell -============================================== - -Description ------------ -Python possesses many mechanisms to invoke an external executable. However, -doing so may present a security issue if appropriate care is not taken to -sanitize any user provided or variable input. - -This plugin test is part of a family of tests built to check for process -spawning and warn appropriately. Specifically, this test looks for the spawning -of a subprocess using a command shell. This type of subprocess invocation is -dangerous as it is vulnerable to various shell injection attacks. Great care -should be taken to sanitize all input in order to mitigate this risk. Calls of -this type are identified by the use of certain commands which are known to use -shells. Bandit will report a MEDIUM severity warning. - -See also: - -- :doc:`linux_commands_wildcard_injection`. -- :doc:`subprocess_without_shell_equals_true`. -- :doc:`start_process_with_no_shell`. -- :doc:`start_process_with_partial_path`. -- :doc:`subprocess_popen_with_shell_equals_true`. - -Available Since ---------------- - - Bandit v0.10.0 - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -This plugin specifically scans for methods listed in `shell` section. - -.. code-block:: yaml - - shell_injection: - shell: - - os.system - - os.popen - - os.popen2 - - os.popen3 - - os.popen4 - - popen2.popen2 - - popen2.popen3 - - popen2.popen4 - - popen2.Popen3 - - popen2.Popen4 - - commands.getoutput - - commands.getstatusoutput - -Sample Output -------------- -.. code-block:: none - - >> Issue: Starting a process with a shell: check for injection. - Severity: Medium Confidence: Medium - Location: examples/os_system.py:3 - 2 - 3 os.system('/bin/echo hi') - -References ----------- -- https://security.openstack.org -- https://docs.python.org/2/library/os.html#os.system -- https://docs.python.org/2/library/subprocess.html#frequently-used-arguments -- https://security.openstack.org/guidelines/dg_use-subprocess-securely.html diff --git a/docs/source/tests/start_process_with_no_shell.rst b/docs/source/tests/start_process_with_no_shell.rst deleted file mode 100644 index f4a7d803..00000000 --- a/docs/source/tests/start_process_with_no_shell.rst +++ /dev/null @@ -1,76 +0,0 @@ - -start_process_with_no_shell -============================================== - -Description ------------ -Python possesses many mechanisms to invoke an external executable. However, -doing so may present a security issue if appropriate care is not taken to -sanitize any user provided or variable input. - -This plugin test is part of a family of tests built to check for process -spawning and warn appropriately. Specifically, this test looks for the spawning -of a subprocess in a way that doesn't use a shell. Although this is generally -safe, it maybe useful for penetration testing workflows to track where external -system calls are used. As such a LOW severity message is generated. - -See also: - -- :doc:`linux_commands_wildcard_injection`. -- :doc:`subprocess_without_shell_equals_true`. -- :doc:`start_process_with_a_shell`. -- :doc:`start_process_with_partial_path`. -- :doc:`subprocess_popen_with_shell_equals_true`. - -Available Since ---------------- - - Bandit v0.10.0 - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -This plugin specifically scans for methods listed in `no_shell` section. - -.. code-block:: yaml - - shell_injection: - no_shell: - - os.execl - - os.execle - - os.execlp - - os.execlpe - - os.execv - - os.execve - - os.execvp - - os.execvpe - - os.spawnl - - os.spawnle - - os.spawnlp - - os.spawnlpe - - os.spawnv - - os.spawnve - - os.spawnvp - - os.spawnvpe - - os.startfile -Sample Output -------------- -.. code-block:: none - - >> Issue: [start_process_with_no_shell] Starting a process without a shell. - Severity: Low Confidence: Medium - Location: examples/os-spawn.py:8 - 7 os.spawnv(mode, path, args) - 8 os.spawnve(mode, path, args, env) - 9 os.spawnvp(mode, file, args) - -References ----------- -- https://security.openstack.org -- https://docs.python.org/2/library/os.html#os.system -- https://docs.python.org/2/library/subprocess.html#frequently-used-arguments -- https://security.openstack.org/guidelines/dg_use-subprocess-securely.html diff --git a/docs/source/tests/start_process_with_partial_path.rst b/docs/source/tests/start_process_with_partial_path.rst deleted file mode 100644 index 1780c285..00000000 --- a/docs/source/tests/start_process_with_partial_path.rst +++ /dev/null @@ -1,74 +0,0 @@ - -start_process_with_partial_path -=============================== - -Description ------------ -Python possesses many mechanisms to invoke an external executable. If the -desired executable path is not fully qualified relative to the filesystem root -then this may present a potential security risk. - -In POSIX environments, the `PATH` environment variable is used to specify a -set of standard locations that will be searched for the first matching named -executable. While convenient, this behavior may allow a malicious actor to -exert control over a system. If they are able to adjust the contents of the -`PATH` variable, or manipulate the file system, then a bogus executable may be -discovered in place of the desired one. This executable will be invoked with the -user privileges of the Python process that spawned it, potentially a highly -privileged user. - -This test will scan the parameters of all configured Python methods, looking -for paths that do not start at the filesystem root, that is, do not have a -leading '/' character. - -Available Since ---------------- - - Bandit v0.13.0 - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -This test will scan parameters of all methods in all sections. Note that methods -are fully qualified and de-aliased prior to checking. - -.. code-block:: yaml - - shell_injection: - # Start a process using the subprocess module, or one of its wrappers. - subprocess: - - subprocess.Popen - - subprocess.call - - # Start a process with a function vulnerable to shell injection. - shell: - - os.system - - os.popen - - popen2.Popen3 - - popen2.Popen4 - - commands.getoutput - - commands.getstatusoutput - # Start a process with a function that is not vulnerable to shell injection. - no_shell: - - os.execl - - os.execle - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Starting a process with a partial executable path - Severity: Low Confidence: High - Location: ./examples/partial_path_process.py:3 - 2 from subprocess import Popen as pop - 3 pop('gcc --version', shell=False) - -References ----------- -- https://security.openstack.org -- https://docs.python.org/2/library/os.html#process-management diff --git a/docs/source/tests/subprocess_popen_with_shell_equals_true.rst b/docs/source/tests/subprocess_popen_with_shell_equals_true.rst deleted file mode 100644 index da69e4de..00000000 --- a/docs/source/tests/subprocess_popen_with_shell_equals_true.rst +++ /dev/null @@ -1,92 +0,0 @@ - -subprocess_popen_with_shell_equals_true -======================================= - -Description ------------ -Python possesses many mechanisms to invoke an external executable. However, -doing so may present a security issue if appropriate care is not taken to -sanitize any user provided or variable input. - -This plugin test is part of a family of tests built to check for process -spawning and warn appropriately. Specifically, this test looks for the spawning -of a subprocess using a command shell. This type of subprocess invocation is -dangerous as it is vulnerable to various shell injection attacks. Great care -should be taken to sanitize all input in order to mitigate this risk. Calls of -this type are identified by a parameter of "shell=True" being given. - -Additionally, this plugin scans the command string given and adjusts its -reported severity based on how it is presented. If the command string is a -simple static string containing no special shell characters, then the resulting -issue has low severity. If the string is static, but contains shell formatting -characters or wildcards, then the reported issue is medium. Finally, if the -string is computed using Python's string manipulation or formatting operations, -then the reported issue has high severity. These severity levels reflect the -likelihood that the code is vulnerable to injection. - -See also: - -- :doc:`linux_commands_wildcard_injection`. -- :doc:`subprocess_without_shell_equals_true`. -- :doc:`start_process_with_no_shell`. -- :doc:`start_process_with_a_shell`. -- :doc:`start_process_with_partial_path`. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -This plugin specifically scans for methods listed in `subprocess` section that -have shell=True specified. - -.. code-block:: yaml - - shell_injection: - - # Start a process using the subprocess module, or one of its wrappers. - subprocess: - - subprocess.Popen - - subprocess.call - - -Sample Output -------------- -.. code-block:: none - - >> Issue: subprocess call with shell=True seems safe, but may be changed in - the future, consider rewriting without shell - Severity: Low Confidence: High - Location: ./examples/subprocess_shell.py:21 - 20 subprocess.check_call(['/bin/ls', '-l'], shell=False) - 21 subprocess.check_call('/bin/ls -l', shell=True) - 22 - - >> Issue: call with shell=True contains special shell characters, consider - moving extra logic into Python code - Severity: Medium Confidence: High - Location: ./examples/subprocess_shell.py:26 - 25 - 26 subprocess.Popen('/bin/ls *', shell=True) - 27 subprocess.Popen('/bin/ls %s' % ('something',), shell=True) - - >> Issue: subprocess call with shell=True identified, security issue. - Severity: High Confidence: High - Location: ./examples/subprocess_shell.py:27 - 26 subprocess.Popen('/bin/ls *', shell=True) - 27 subprocess.Popen('/bin/ls %s' % ('something',), shell=True) - 28 subprocess.Popen('/bin/ls {}'.format('something'), shell=True) - -References ----------- -- https://security.openstack.org -- https://docs.python.org/2/library/subprocess.html#frequently-used-arguments -- https://security.openstack.org/guidelines/dg_use-subprocess-securely.html -- https://security.openstack.org/guidelines/dg_avoid-shell-true.html diff --git a/docs/source/tests/subprocess_without_shell_equals_true.rst b/docs/source/tests/subprocess_without_shell_equals_true.rst deleted file mode 100644 index 6d1666a9..00000000 --- a/docs/source/tests/subprocess_without_shell_equals_true.rst +++ /dev/null @@ -1,68 +0,0 @@ - -subprocess_without_shell_equals_true -============================================== - -Description ------------ -Python possesses many mechanisms to invoke an external executable. However, -doing so may present a security issue if appropriate care is not taken to -sanitize any user provided or variable input. - -This plugin test is part of a family of tests built to check for process -spawning and warn appropriately. Specifically, this test looks for the spawning -of a subprocess without the use of a command shell. This type of subprocess -invocation is not vulnerable to shell injection attacks, but care should still -be taken to ensure validity of input. - -Because this is a lesser issue than that described in -`subprocess_popen_with_shell_equals_true` a LOW severity warning is reported. - -See also: - -- :doc:`linux_commands_wildcard_injection`. -- :doc:`subprocess_popen_with_shell_equals_true`. -- :doc:`start_process_with_no_shell`. -- :doc:`start_process_with_a_shell`. -- :doc:`start_process_with_partial_path`. - -Available Since ---------------- - - Bandit v0.9.0 - -Config Options --------------- -This plugin test shares a configuration with others in the same family, namely -`shell_injection`. This configuration is divided up into three sections, -`subprocess`, `shell` and `no_shell`. They each list Python calls that spawn -subprocesses, invoke commands within a shell, or invoke commands without a -shell (by replacing the calling process) respectively. - -This plugin specifically scans for methods listed in `subprocess` section that -have shell=False specified. - -.. code-block:: yaml - - shell_injection: - # Start a process using the subprocess module, or one of its wrappers. - subprocess: - - subprocess.Popen - - subprocess.call - - -Sample Output -------------- -.. code-block:: none - - >> Issue: subprocess call - check for execution of untrusted input. - Severity: Low Confidence: High - Location: ./examples/subprocess_shell.py:23 - 22 - 23 subprocess.check_output(['/bin/ls', '-l']) - 24 - -References ----------- -- https://security.openstack.org -- https://docs.python.org/2/library/subprocess.html#frequently-used-arguments -- https://security.openstack.org/guidelines/dg_avoid-shell-true.html -- https://security.openstack.org/guidelines/dg_use-subprocess-securely.html diff --git a/docs/source/tests/try_except_pass.rst b/docs/source/tests/try_except_pass.rst deleted file mode 100644 index 80aad947..00000000 --- a/docs/source/tests/try_except_pass.rst +++ /dev/null @@ -1,66 +0,0 @@ - -try_except_pass -=============== - -Description ------------ -Errors in Python code bases are typically communicated using ``Exceptions``. -An exception object is 'raised' in the event of an error and can be 'caught' at -a later point in the program, typically some error handling or logging action -will then be performed. - -However, it is possible to catch an exception and silently ignore it. This is -illustrated with the following example - -.. code-block:: python - - try: - do_some_stuff() - except Exception: - pass - -This pattern is considered bad practice in general, but also represents a -potential security issue. A larger than normal volume of errors from a service -can indicate an attempt is being made to disrupt or interfere with it. Thus -errors should, at the very least, be logged. - -There are rare situations where it is desirable to suppress errors, but this is -typically done with specific exception types, rather than the base Exception -class (or no type). To accommodate this, the test may be configured to ignore -'try, except, pass' where the exception is typed. For example, the following -would not generate a warning if the configuration option -``checked_typed_exception`` is set to False: - -.. code-block:: python - - try: - do_some_stuff() - except ZeroDivisionError: - pass - -Available Since ---------------- - - Bandit v0.13.0 - -Config Options --------------- -.. code-block:: yaml - - try_except_pass: - check_typed_exception: True - - -Sample Output -------------- -.. code-block:: none - - >> Issue: Try, Except, Pass detected. - Severity: Low Confidence: High - Location: ./examples/try_except_pass.py:4 - 3 a = 1 - 4 except: - 5 pass - -References ----------- -- https://security.openstack.org diff --git a/docs/source/tests/use_of_mako_templates.rst b/docs/source/tests/use_of_mako_templates.rst deleted file mode 100644 index 905033e6..00000000 --- a/docs/source/tests/use_of_mako_templates.rst +++ /dev/null @@ -1,47 +0,0 @@ - -use_of_mako_templates -===================== - -Description ------------ -Mako is a Python templating system often used to build web applications. It is -the default templating system used in Pylons and Pyramid. Unlike Jinja2 (an -alternative templating system), Mako has no environment wide variable escaping -mechanism. Because of this, all input variables must be carefully escaped before -use to prevent possible vulnerabilities to Cross Site Scripting (XSS) attacks. - -See also: - -- :doc:`jinja2_autoescape_false`. - - -Available Since ---------------- - - Bandit v0.10.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: Mako templates allow HTML/JS rendering by default and are - inherently open to XSS attacks. Ensure variables in all templates are - properly sanitized via the 'n', 'h' or 'x' flags (depending on context). - For example, to HTML escape the variable 'data' do ${ data |h }. - Severity: Medium Confidence: High - Location: ./examples/mako_templating.py:10 - 9 - 10 mako.template.Template("hern") - 11 template.Template("hern") - - -References ----------- -- http://www.makotemplates.org/ -- https://www.owasp.org/index.php/Cross-site_Scripting_(XSS) -- https://security.openstack.org -- https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html - diff --git a/docs/source/tests/weak_cryptographic_key.rst b/docs/source/tests/weak_cryptographic_key.rst deleted file mode 100644 index a6d2027c..00000000 --- a/docs/source/tests/weak_cryptographic_key.rst +++ /dev/null @@ -1,36 +0,0 @@ - -weak_cryptographic_key -====================== - -Description ------------ -As computational power increases, so does the ability to break ciphers with -smaller key lengths. The recommended key length size is 2048 and higher. 1024 -bits and below are now considered breakable. This plugin test checks for use -of any key less than 2048 bits and returns a high severity error if lower than -1024 and a medium severity error greater than 1024 but less than 2048. - -Available Since ---------------- - - Bandit v0.14.0 - -Config Options --------------- -None - -Sample Output -------------- -.. code-block:: none - - >> Issue: DSA key sizes below 1024 bits are considered breakable. - Severity: High Confidence: High - Location: examples/weak_cryptographic_key_sizes.py:36 - 35 # Also incorrect: without keyword args - 36 dsa.generate_private_key(512, - 37 backends.default_backend()) - 38 rsa.generate_private_key(3, - -References ----------- - - http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf - - https://security.openstack.org/guidelines/dg_strong-crypto.html diff --git a/setup.cfg b/setup.cfg index 949fad38..c6fc5932 100644 --- a/setup.cfg +++ b/setup.cfg @@ -113,8 +113,8 @@ data_files = [build_sphinx] all_files = 1 -build-dir = docs/build -source-dir = docs/source +build-dir = doc/build +source-dir = doc/source [pbr] autodoc_tree_index_modules = True