bandit.plugins package

Submodules

bandit.plugins.app_debug module

B201: Test for use of flask app with debug set to true

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].

Example:
>> 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

New in version 0.15.0.

bandit.plugins.app_debug.flask_debug_true(context)

bandit.plugins.asserts module

B101: Test for use of assert

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

Example:
>> 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()

New in version 0.11.0.

bandit.plugins.asserts.assert_used(context)

bandit.plugins.crypto_request_no_cert_validation module

B501: Test for missing certificate validation

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.

Example:
>> 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)

New in version 0.9.0.

bandit.plugins.crypto_request_no_cert_validation.request_with_no_cert_validation(context)

bandit.plugins.exec module

B102: Test for the use of exec

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.

Example:
>> Issue: Use of exec detected.
   Severity: Medium   Confidence: High
   Location: ./examples/exec-py2.py:2
1 exec("do evil")
2 exec "do evil"

See also

New in version 0.9.0.

bandit.plugins.exec.exec_issue()
bandit.plugins.exec.exec_used(context)

bandit.plugins.exec_as_root module

B111: Test for the use of rootwrap running as root

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.

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
Example:
>> 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

New in version 0.10.0.

bandit.plugins.exec_as_root.execute_with_run_as_root_equals_true(context, config)
bandit.plugins.exec_as_root.gen_config(name)

bandit.plugins.general_bad_file_permissions module

B103: Test for setting permissive file permissions

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.

Example:
>> 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

New in version 0.9.0.

bandit.plugins.general_bad_file_permissions.set_bad_file_permissions(context)

bandit.plugins.general_bind_all_interfaces module

B104: Test for binding to all interfaces

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.

Example:
>> 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))

See also

  • __TODO__ : add best practice info on binding to all interfaces, and link here.

New in version 0.9.0.

bandit.plugins.general_bind_all_interfaces.hardcoded_bind_all_interfaces(context)

bandit.plugins.general_hardcoded_password module

bandit.plugins.general_hardcoded_password.hardcoded_password_default(context)

B107: Test for use of hard-coded password argument defaults

The use of hard-coded passwords increases the possibility of password guessing tremendously. This plugin test looks for all function definitions that specify a default string literal for some argument. It checks that the argument does not look like a password.

Variables are considered to look like a password if they have match any one of:

  • “password”
  • “pass”
  • “passwd”
  • “pwd”
  • “secret”
  • “token”
  • “secrete”

Note: this can be noisy and may generate false positives.

Config Options:

None

Example:
>> Issue: [B107:hardcoded_password_default] Possible hardcoded
password: 'Admin'
   Severity: Low   Confidence: Medium
   Location: ./examples/hardcoded-passwords.py:1

1    def someFunction(user, password="Admin"):
2      print("Hi " + user)

New in version 0.9.0.

bandit.plugins.general_hardcoded_password.hardcoded_password_funcarg(context)

B106: Test for use of hard-coded password function arguments

The use of hard-coded passwords increases the possibility of password guessing tremendously. This plugin test looks for all function calls being passed a keyword argument that is a string literal. It checks that the assigned local variable does not look like a password.

Variables are considered to look like a password if they have match any one of:

  • “password”
  • “pass”
  • “passwd”
  • “pwd”
  • “secret”
  • “token”
  • “secrete”

Note: this can be noisy and may generate false positives.

Config Options:

None

Example:
>> Issue: [B106:hardcoded_password_funcarg] Possible hardcoded
password: 'blerg'
   Severity: Low   Confidence: Medium
   Location: ./examples/hardcoded-passwords.py:16
15
16    doLogin(password="blerg")

New in version 0.9.0.

bandit.plugins.general_hardcoded_password.hardcoded_password_string(context)

B105: Test for use of hard-coded password strings

The use of hard-coded passwords increases the possibility of password guessing tremendously. This plugin test looks for all string literals and checks the following conditions:

  • assigned to a variable that looks like a password
  • assigned to a dict key that looks like a password
  • used in a comparison with a variable that looks like a password

Variables are considered to look like a password if they have match any one of:

  • “password”
  • “pass”
  • “passwd”
  • “pwd”
  • “secret”
  • “token”
  • “secrete”

Note: this can be noisy and may generate false positives.

Config Options:

None

Example:
>> 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")

New in version 0.9.0.

bandit.plugins.general_hardcoded_tmp module

B108: Test for insecure usage of tmp file/directory

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.

hardcoded_tmp_directory:
    tmp_dirs: ['/tmp', '/var/tmp', '/dev/shm']
Example:

New in version 0.9.0.

bandit.plugins.general_hardcoded_tmp.gen_config(name)
bandit.plugins.general_hardcoded_tmp.hardcoded_tmp_directory(context, config)

bandit.plugins.hashlib_new_insecure_functions module

B324: Test for use of insecure md4 and md5 hash functions in hashlib.new()

This plugin checks for the usage of the insecure MD4 and MD5 hash functions in hashlib.new function. The hashlib.new function provides the ability to construct a new hashing object using the named algorithm. This can be used to create insecure hash functions like MD4 and MD5 if they are passed as algorithm names to this function.

This is similar to B303 blacklist check, except that this checks for insecure hash functions created using hashlib.new function.

Example:
>> Issue: [B324:hashlib_new] Use of insecure MD4 or MD5 hash function.

Severity: Medium Confidence: High Location: examples/hashlib_new_insecure_funcs.py:3

2 3 md5_hash = hashlib.new(‘md5’, string=’test’) 4 print(md5_hash)

New in version 1.5.0.

bandit.plugins.hashlib_new_insecure_functions.hashlib_new(context)

bandit.plugins.injection_paramiko module

B601: Test for shell injection within Paramiko

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.

Example:
>> 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

New in version 0.12.0.

bandit.plugins.injection_paramiko.paramiko_calls(context)

bandit.plugins.injection_shell module

bandit.plugins.injection_shell.any_other_function_with_shell_equals_true(context, config)

B604: Test for any 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:

  • ../plugins/linux_commands_wildcard_injection
  • ../plugins/subprocess_popen_with_shell_equals_true
  • ../plugins/subprocess_without_shell_equals_true
  • ../plugins/start_process_with_no_shell
  • ../plugins/start_process_with_a_shell
  • ../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.

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]
Example:
>> 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

New in version 0.9.0.

bandit.plugins.injection_shell.gen_config(name)
bandit.plugins.injection_shell.start_process_with_a_shell(context, config)

B605: Test for starting a 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 LOW severity warning.

See also:

  • ../plugins/linux_commands_wildcard_injection
  • ../plugins/subprocess_without_shell_equals_true
  • ../plugins/start_process_with_no_shell
  • ../plugins/start_process_with_partial_path
  • ../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.

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
Example:
>> Issue: Starting a process with a shell: check for injection.
   Severity: Low   Confidence: Medium
   Location: examples/os_system.py:3
2
3   os.system('/bin/echo hi')

New in version 0.10.0.

bandit.plugins.injection_shell.start_process_with_no_shell(context, config)

B606: Test for starting a 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:

  • ../plugins/linux_commands_wildcard_injection
  • ../plugins/subprocess_without_shell_equals_true
  • ../plugins/start_process_with_a_shell
  • ../plugins/start_process_with_partial_path
  • ../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.

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
Example:
>> 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)

New in version 0.10.0.

bandit.plugins.injection_shell.start_process_with_partial_path(context, config)

B607: Test for starting a process with a 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.

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
Example:
>> 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)

New in version 0.13.0.

bandit.plugins.injection_shell.subprocess_popen_with_shell_equals_true(context, config)

B602: Test for use of 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:

  • ../plugins/linux_commands_wildcard_injection
  • ../plugins/subprocess_without_shell_equals_true
  • ../plugins/start_process_with_no_shell
  • ../plugins/start_process_with_a_shell
  • ../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.

shell_injection:

    # Start a process using the subprocess module, or one of its
    wrappers.
    subprocess:
        - subprocess.Popen
        - subprocess.call
Example:
>> 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)

New in version 0.9.0.

bandit.plugins.injection_shell.subprocess_without_shell_equals_true(context, config)

B603: Test for use of subprocess 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 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:

  • ../plugins/linux_commands_wildcard_injection
  • ../plugins/subprocess_popen_with_shell_equals_true
  • ../plugins/start_process_with_no_shell
  • ../plugins/start_process_with_a_shell
  • ../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.

shell_injection:
    # Start a process using the subprocess module, or one of its
    wrappers.
    subprocess:
        - subprocess.Popen
        - subprocess.call
Example:
>> 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

New in version 0.9.0.

bandit.plugins.injection_sql module

B608: Test for SQL injection

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 + …
  • “SELECT {} FROM derp;”.format(var)

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)
Example:
>> 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

New in version 0.9.0.

bandit.plugins.injection_sql.hardcoded_sql_expressions(context)

bandit.plugins.injection_wildcard module

B609: Test for use of wildcard injection

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.

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
Example:
>> 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 *")

New in version 0.9.0.

bandit.plugins.injection_wildcard.linux_commands_wildcard_injection(context, config)

bandit.plugins.insecure_ssl_tls module

bandit.plugins.insecure_ssl_tls.gen_config(name)
bandit.plugins.insecure_ssl_tls.get_bad_proto_versions(config)
bandit.plugins.insecure_ssl_tls.ssl_with_bad_defaults(context, config)

B503: 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 ../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:

  • ../plugins/ssl_with_bad_version
  • ../plugins/ssl_with_no_version

Config Options:

This test shares the configuration provided for the standard ../plugins/ssl_with_bad_version test, please refer to its documentation.

Example:
>> 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

New in version 0.9.0.

bandit.plugins.insecure_ssl_tls.ssl_with_bad_version(context, config)

B502: 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:

  • ../plugins/ssl_with_bad_defaults
  • ../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:

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
Example:
>> 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)

New in version 0.9.0.

bandit.plugins.insecure_ssl_tls.ssl_with_no_version(context)

B504: 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 ../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:

  • ../plugins/ssl_with_bad_version
  • ../plugins/ssl_with_bad_defaults

Config Options:

This test shares the configuration provided for the standard ../plugins/ssl_with_bad_version test, please refer to its documentation.

Example:
>> 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

New in version 0.9.0.

bandit.plugins.jinja2_templates module

B701: Test for not auto escaping in jinja2

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.

Example:
>> 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 or use the select_autoescape function to mitigate XSS
vulnerabilities.
   Severity: High   Confidence: High
   Location: ./examples/jinja2_templating.py:15
14
15  Environment(loader=templateLoader,
16              load=templateLoader)
17
18  Environment(autoescape=select_autoescape(['html', 'htm', 'xml']),
19              loader=templateLoader)

New in version 0.10.0.

bandit.plugins.jinja2_templates.jinja2_autoescape_false(context)

bandit.plugins.mako_templates module

B702: Test for use of mako templates

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.

Example:
>> 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")

New in version 0.10.0.

bandit.plugins.mako_templates.use_of_mako_templates(context)

bandit.plugins.secret_config_option module

B109: Test for a password based config option not marked secret

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:

password_config_option_not_marked_secret:
    function_names:
        - oslo.config.cfg.StrOpt
        - oslo_config.cfg.StrOpt
Example:
>> 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 identified, 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',

New in version 0.10.0.

bandit.plugins.secret_config_option.gen_config(name)
bandit.plugins.secret_config_option.password_config_option_not_marked_secret(context, config)

bandit.plugins.try_except_continue module

B112: Test for a continue in the except block

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 while in a loop. This is illustrated with the following example

while keep_going:
  try:
    do_some_stuff()
  except Exception:
    continue

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, continue’ 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:

while keep_going:
  try:
    do_some_stuff()
  except ZeroDivisionError:
    continue

Config Options:

try_except_continue:
  check_typed_exception: True
Example:
>> Issue: Try, Except, Continue detected.
   Severity: Low   Confidence: High
   Location: ./examples/try_except_continue.py:5
4            a = i
5        except:
6            continue

New in version 1.0.0.

bandit.plugins.try_except_continue.gen_config(name)
bandit.plugins.try_except_continue.try_except_continue(context, config)

bandit.plugins.try_except_pass module

B110: Test for a pass in the except block

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

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:

try:
  do_some_stuff()
except ZeroDivisionError:
  pass

Config Options:

try_except_pass:
  check_typed_exception: True
Example:
>> Issue: Try, Except, Pass detected.
   Severity: Low   Confidence: High
   Location: ./examples/try_except_pass.py:4
3        a = 1
4    except:
5        pass

New in version 0.13.0.

bandit.plugins.try_except_pass.gen_config(name)
bandit.plugins.try_except_pass.try_except_pass(context, config)

bandit.plugins.weak_cryptographic_key module

B505: Test for weak cryptographic key use

As computational power increases, so does the ability to break ciphers with smaller key lengths. The recommended key length size for RSA and DSA algorithms is 2048 and higher. 1024 bits and below are now considered breakable. EC key length sizes are recommended to be 224 and higher with 160 and below considered breakable. This plugin test checks for use of any key less than those limits and returns a high severity error if lower than the lower threshold and a medium severity error for those lower than the higher threshold.

Example:
>> 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,

New in version 0.14.0.

bandit.plugins.weak_cryptographic_key.gen_config(name)
bandit.plugins.weak_cryptographic_key.weak_cryptographic_key(context, config)

bandit.plugins.yaml_load module

B506: Test for use of yaml load

This plugin test checks for the unsafe usage of the yaml.load function from the PyYAML package. The yaml.load function provides the ability to construct an arbitrary Python object, which may be dangerous if you receive a YAML document from an untrusted source. The function yaml.safe_load limits this ability to simple Python objects like integers or lists.

Please see http://pyyaml.org/wiki/PyYAMLDocumentation#LoadingYAML for more information on yaml.load and yaml.safe_load

Example:
>> Issue: [yaml_load] Use of unsafe yaml load. Allows instantiation of

arbitrary objects. Consider yaml.safe_load(). Severity: Medium Confidence: High Location: examples/yaml_load.py:5

4 ystr = yaml.dump({‘a’ : 1, ‘b’ : 2, ‘c’ : 3}) 5 y = yaml.load(ystr) 6 yaml.dump(y)

New in version 1.0.0.

bandit.plugins.yaml_load.yaml_load(context)

Module contents