Repository: PyCQA/bandit
Pull request #924 (2022-07-08 03:31:39)

Fixup some invalid pickle testing
* cPickle doesn't exist in Python 3+, therefore we can drop
* examples/pickle_deserialize.py uses StringIO.StringIO which was
  replaced with io.StringIO. However, these calls expect bytes, not str
* Similarly examples/dill.py using StringIO to be replaced with BytesIO.
  It was also using an instance of an non-existant class name of Undillr
  and not Unpickler.

Signed-off-by: Eric Brown <eric_wade_brown@yahoo.com>


Patch:
diff --git a/bandit/blacklists/calls.py b/bandit/blacklists/calls.py
index 079da90..37ad101 100644
--- a/bandit/blacklists/calls.py
+++ b/bandit/blacklists/calls.py
@@ -24,9 +24,6 @@ deserialize untrusted data, possible security issue.
 | B301 | pickle              | - pickle.loads                     | Medium    |
 |      |                     | - pickle.load                      |           |
 |      |                     | - pickle.Unpickler                 |           |
-|      |                     | - cPickle.loads                    |           |
-|      |                     | - cPickle.load                     |           |
-|      |                     | - cPickle.Unpickler                |           |
 |      |                     | - dill.loads                       |           |
 |      |                     | - dill.load                        |           |
 |      |                     | - dill.Unpickler                   |           |
@@ -35,6 +32,7 @@ deserialize untrusted data, possible security issue.
 |      |                     | - jsonpickle.decode                |           |
 |      |                     | - jsonpickle.unpickler.decode      |           |
 |      |                     | - jsonpickle.unpickler.Unpickler   |           |
+|      |                     | - pandas.read_pickle               |           |
 +------+---------------------+------------------------------------+-----------+
 
 B302: marshal
@@ -347,9 +345,6 @@ def gen_blacklist():
                 "pickle.loads",
                 "pickle.load",
                 "pickle.Unpickler",
-                "cPickle.loads",
-                "cPickle.load",
-                "cPickle.Unpickler",
                 "dill.loads",
                 "dill.load",
                 "dill.Unpickler",
@@ -358,6 +353,7 @@ def gen_blacklist():
                 "jsonpickle.decode",
                 "jsonpickle.unpickler.decode",
                 "jsonpickle.unpickler.Unpickler",
+                "pandas.read_pickle",
             ],
             "Pickle and modules that wrap it can be unsafe when used to "
             "deserialize untrusted data, possible security issue.",
diff --git a/bandit/core/context.py b/bandit/core/context.py
index 801b364..1ecfb44 100644
--- a/bandit/core/context.py
+++ b/bandit/core/context.py
@@ -276,9 +276,8 @@ class Context:
         """
         max_args = self.call_args_count
         if max_args and position_num < max_args:
-            return self._get_literal_value(
-                self._context["call"].args[position_num]
-            )
+            arg = self._context["call"].args[position_num]
+            return getattr(arg, "attr", None) or self._get_literal_value(arg)
         else:
             return None
 
diff --git a/bandit/core/manager.py b/bandit/core/manager.py
index fe20a2d..e82f671 100644
--- a/bandit/core/manager.py
+++ b/bandit/core/manager.py
@@ -331,12 +331,12 @@ class BanditManager:
             new_files_list.remove(fname)
         except Exception as e:
             LOG.error(
-                "Exception occurred when executing tests against %s.",
-                fname,
-                fname,
+                "Exception occurred when executing tests against %s.", fname
             )
             if not LOG.isEnabledFor(logging.DEBUG):
-                LOG.error('Run "bandit --debug %s" to see the full traceback.')
+                LOG.error(
+                    'Run "bandit --debug %s" to see the full traceback.', fname
+                )
 
             self.skipped.append((fname, "exception while scanning file"))
             new_files_list.remove(fname)
diff --git a/bandit/plugins/exec.py b/bandit/plugins/exec.py
index 3c309d5..42354db 100644
--- a/bandit/plugins/exec.py
+++ b/bandit/plugins/exec.py
@@ -23,7 +23,6 @@ Python docs succinctly describe why the use of `exec` is risky.
 
 .. seealso::
 
- - https://docs.python.org/2/reference/simple_stmts.html#exec
  - https://docs.python.org/3/library/functions.html#exec
  - https://www.python.org/dev/peps/pep-0551/#background
  - https://www.python.org/dev/peps/pep-0578/#suggested-audit-hook-locations
diff --git a/bandit/plugins/general_bad_file_permissions.py b/bandit/plugins/general_bad_file_permissions.py
index 68e091b..7d3fce4 100644
--- a/bandit/plugins/general_bad_file_permissions.py
+++ b/bandit/plugins/general_bad_file_permissions.py
@@ -14,8 +14,8 @@ 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.
+a file is set to group write or executable and a HIGH warning is reported if a
+file is set world write or executable. Warnings are given with HIGH confidence.
 
 :Example:
 
@@ -49,6 +49,9 @@ set world writable. Warnings are given with HIGH confidence.
 .. versionchanged:: 1.7.3
     CWE information added
 
+.. versionchanged:: 1.7.5
+    Added checks for S_IWGRP and S_IXOTH
+
 """  # noqa: E501
 import stat
 
@@ -57,6 +60,15 @@ from bandit.core import issue
 from bandit.core import test_properties as test
 
 
+def _stat_is_dangerous(mode):
+    return (
+        mode & stat.S_IWOTH
+        or mode & stat.S_IWGRP
+        or mode & stat.S_IXGRP
+        or mode & stat.S_IXOTH
+    )
+
+
 @test.checks("Call")
 @test.test_id("B103")
 def set_bad_file_permissions(context):
@@ -67,7 +79,7 @@ def set_bad_file_permissions(context):
             if (
                 mode is not None
                 and isinstance(mode, int)
-                and (mode & stat.S_IWOTH or mode & stat.S_IXGRP)
+                and _stat_is_dangerous(mode)
             ):
                 # world writable is an HIGH, group executable is a MEDIUM
                 if mode & stat.S_IWOTH:
diff --git a/bandit/plugins/insecure_ssl_tls.py b/bandit/plugins/insecure_ssl_tls.py
index 80f2e5c..319abcf 100644
--- a/bandit/plugins/insecure_ssl_tls.py
+++ b/bandit/plugins/insecure_ssl_tls.py
@@ -22,6 +22,8 @@ def gen_config(name):
                 "PROTOCOL_TLSv1",  # strict option
                 "SSLv3_METHOD",  # strict option
                 "TLSv1_METHOD",
+                "PROTOCOL_TLSv1_1",
+                "TLSv1_1_METHOD",
             ]
         }  # strict option
 
@@ -106,6 +108,9 @@ def ssl_with_bad_version(context, config):
     .. versionchanged:: 1.7.3
         CWE information added
 
+    .. versionchanged:: 1.7.5
+        Added TLS 1.1
+
     """
     bad_ssl_versions = get_bad_proto_versions(config)
     if context.call_function_name_qual == "ssl.wrap_socket":
@@ -196,6 +201,9 @@ def ssl_with_bad_defaults(context, config):
     .. versionchanged:: 1.7.3
         CWE information added
 
+    .. versionchanged:: 1.7.5
+        Added TLS 1.1
+
     """
 
     bad_ssl_versions = get_bad_proto_versions(config)
diff --git a/bandit/plugins/jinja2_templates.py b/bandit/plugins/jinja2_templates.py
index f0b23e0..667b79d 100644
--- a/bandit/plugins/jinja2_templates.py
+++ b/bandit/plugins/jinja2_templates.py
@@ -104,9 +104,10 @@ def jinja2_autoescape_false(context):
                         ):
                             return
                         # Check if select_autoescape function is used.
-                        elif (
-                            isinstance(value, ast.Call)
-                            and getattr(value.func, "id", None)
+                        elif isinstance(value, ast.Call) and (
+                            getattr(value.func, "attr", None)
+                            == "select_autoescape"
+                            or getattr(value.func, "id", None)
                             == "select_autoescape"
                         ):
                             return
diff --git a/bandit/plugins/request_without_timeout.py b/bandit/plugins/request_without_timeout.py
index d39fd8f..9aa80bf 100644
--- a/bandit/plugins/request_without_timeout.py
+++ b/bandit/plugins/request_without_timeout.py
@@ -38,7 +38,7 @@ Bandit will return a MEDIUM severity error.
 
 .. seealso::
 
- - https://2.python-requests.org/en/master/user/quickstart/#timeouts
+ - https://requests.readthedocs.io/en/latest/user/advanced/#timeouts
 
 .. versionadded:: 1.7.5
 
diff --git a/bandit/plugins/tarfile_unsafe_members.py b/bandit/plugins/tarfile_unsafe_members.py
new file mode 100644
index 0000000..32c1e61
--- /dev/null
+++ b/bandit/plugins/tarfile_unsafe_members.py
@@ -0,0 +1,109 @@
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+r"""
+=================================
+B202: Test for tarfile.extractall
+=================================
+
+This plugin will look for usage of ``tarfile.extractall()``
+
+Severity are set as follows:
+
+* ``tarfile.extractalll(members=function(tarfile))`` - LOW
+* ``tarfile.extractalll(members=?)`` - member is not a function - MEDIUM
+* ``tarfile.extractall()`` - members from the archive is trusted - HIGH
+
+Use ``tarfile.extractall(members=function_name)`` and define a function
+that will inspect each member. Discard files that contain a directory
+traversal sequences such as ``../`` or ``\..`` along with all special filetypes
+unless you explicitly need them.
+
+:Example:
+
+.. code-block:: none
+
+    >> Issue: [B202:tarfile_unsafe_members] tarfile.extractall used without
+    any validation. You should check members and discard dangerous ones
+    Severity: High   Confidence: High
+    CWE: CWE-22 (https://cwe.mitre.org/data/definitions/22.html)
+    Location: examples/tarfile_extractall.py:8
+    More Info:
+    https://bandit.readthedocs.io/en/latest/plugins/b202_tarfile_unsafe_members.html
+    7	    tar = tarfile.open(filename)
+    8	    tar.extractall(path=tempfile.mkdtemp())
+    9	    tar.close()
+
+
+.. seealso::
+
+ - https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall
+ - https://docs.python.org/3/library/tarfile.html#tarfile.TarInfo
+
+.. versionadded:: 1.7.5
+
+"""
+import ast
+
+import bandit
+from bandit.core import issue
+from bandit.core import test_properties as test
+
+
+def exec_issue(level, members=""):
+    if level == bandit.LOW:
+        return bandit.Issue(
+            severity=bandit.LOW,
+            confidence=bandit.LOW,
+            cwe=issue.Cwe.PATH_TRAVERSAL,
+            text="Usage of tarfile.extractall(members=function(tarfile)). "
+            "Make sure your function properly discards dangerous members "
+            "{members}).".format(members=members),
+        )
+    elif level == bandit.MEDIUM:
+        return bandit.Issue(
+            severity=bandit.MEDIUM,
+            confidence=bandit.MEDIUM,
+            cwe=issue.Cwe.PATH_TRAVERSAL,
+            text="Found tarfile.extractall(members=?) but couldn't "
+            "identify the type of members. "
+            "Check if the members were properly validated "
+            "{members}).".format(members=members),
+        )
+    else:
+        return bandit.Issue(
+            severity=bandit.HIGH,
+            confidence=bandit.HIGH,
+            cwe=issue.Cwe.PATH_TRAVERSAL,
+            text="tarfile.extractall used without any validation. "
+            "Please check and discard dangerous members.",
+        )
+
+
+def get_members_value(context):
+    for keyword in context.node.keywords:
+        if keyword.arg == "members":
+            arg = keyword.value
+            if isinstance(arg, ast.Call):
+                return {"Function": arg.func.id}
+            else:
+                value = arg.id if isinstance(arg, ast.Name) else arg
+                return {"Other": value}
+
+
+@test.test_id("B202")
+@test.checks("Call")
+def tarfile_unsafe_members(context):
+    if all(
+        [
+            context.is_module_imported_exact("tarfile"),
+            "extractall" in context.call_function_name,
+        ]
+    ):
+        if "members" in context.call_keywords:
+            members = get_members_value(context)
+            if "Function" in members:
+                return exec_issue(bandit.LOW, members)
+            else:
+                return exec_issue(bandit.MEDIUM, members)
+        return exec_issue(bandit.HIGH)
diff --git a/bandit/plugins/weak_cryptographic_key.py b/bandit/plugins/weak_cryptographic_key.py
index db91cb2..da73ced 100644
--- a/bandit/plugins/weak_cryptographic_key.py
+++ b/bandit/plugins/weak_cryptographic_key.py
@@ -131,9 +131,9 @@ def _weak_crypto_key_size_cryptography_io(context, config):
             "SECT163K1": 163,
             "SECT163R2": 163,
         }
-        curve = (
-            context.get_call_arg_value("curve")
-            or context.call_args[arg_position[key_type]]
+        curve = context.get_call_arg_value("curve") or (
+            len(context.call_args) > arg_position[key_type]
+            and context.call_args[arg_position[key_type]]
         )
         key_size = curve_key_sizes[curve] if curve in curve_key_sizes else 224
         return _classify_key_size(config, key_type, key_size)
diff --git a/bandit/plugins/yaml_load.py b/bandit/plugins/yaml_load.py
index acd67d7..2304c1d 100644
--- a/bandit/plugins/yaml_load.py
+++ b/bandit/plugins/yaml_load.py
@@ -62,6 +62,8 @@ def yaml_load(context):
             func == "load",
             not context.check_call_arg_value("Loader", "SafeLoader"),
             not context.check_call_arg_value("Loader", "CSafeLoader"),
+            not context.get_call_arg_at_position(1) == "SafeLoader",
+            not context.get_call_arg_at_position(1) == "CSafeLoader",
         ]
     ):
         return bandit.Issue(
diff --git a/doc/source/plugins/b202_tarfile_unsafe_members.rst b/doc/source/plugins/b202_tarfile_unsafe_members.rst
new file mode 100644
index 0000000..3b99055
--- /dev/null
+++ b/doc/source/plugins/b202_tarfile_unsafe_members.rst
@@ -0,0 +1,5 @@
+----------------------------
+B202: tarfile_unsafe_members
+----------------------------
+
+.. automodule:: bandit.plugins.tarfile_unsafe_members
diff --git a/examples/dill.py b/examples/dill.py
index fbb9111..beb1e57 100644
--- a/examples/dill.py
+++ b/examples/dill.py
@@ -1,14 +1,14 @@
 import dill
-import StringIO
+import io
 
 # dill
 pick = dill.dumps({'a': 'b', 'c': 'd'})
 print(dill.loads(pick))
 
-file_obj = StringIO.StringIO()
+file_obj = io.BytesIO()
 dill.dump([1, 2, '3'], file_obj)
 file_obj.seek(0)
 print(dill.load(file_obj))
 
 file_obj.seek(0)
-print(dill.Undillr(file_obj).load())
+print(dill.Unpickler(file_obj).load())
diff --git a/examples/jinja2_templating.py b/examples/jinja2_templating.py
index d5aaa2d..0dce14d 100644
--- a/examples/jinja2_templating.py
+++ b/examples/jinja2_templating.py
@@ -20,6 +20,9 @@ Environment(loader=templateLoader, autoescape=select_autoescape())
 Environment(loader=templateLoader,
             autoescape=select_autoescape(['html', 'htm', 'xml']))
 
+Environment(loader=templateLoader,
+            autoescape=jinja2.select_autoescape(['html', 'htm', 'xml']))
+
 
 def fake_func():
     return 'foobar'
diff --git a/examples/os-chmod.py b/examples/os-chmod.py
index 65560f6..f7fff85 100644
--- a/examples/os-chmod.py
+++ b/examples/os-chmod.py
@@ -14,4 +14,6 @@ os.chmod('~/.bashrc', 511)
 os.chmod('/etc/hosts', 0o777)
 os.chmod('/tmp/oh_hai', 0x1ff)
 os.chmod('/etc/passwd', stat.S_IRWXU)
-os.chmod(key_file, 0o777)
+os.chmod(keyfile, 0o777)
+os.chmod('~/hidden_exec', stat.S_IXGRP)
+os.chmod('~/hidden_exec', stat.S_IXOTH)
diff --git a/examples/pandas_read_pickle.py b/examples/pandas_read_pickle.py
new file mode 100644
index 0000000..61174f6
--- /dev/null
+++ b/examples/pandas_read_pickle.py
@@ -0,0 +1,12 @@
+import pickle
+import pandas as pd
+
+
+df = pd.DataFrame(
+    {
+        "col_A": [1, 2]
+    }
+)
+pick = pickle.dumps(df)
+
+print(pd.read_pickle(pick))
diff --git a/examples/pickle_deserialize.py b/examples/pickle_deserialize.py
index 4c405bb..3c56c80 100644
--- a/examples/pickle_deserialize.py
+++ b/examples/pickle_deserialize.py
@@ -1,29 +1,15 @@
-import cPickle
+import io
 import pickle
-import StringIO
 
 
 # pickle
 pick = pickle.dumps({'a': 'b', 'c': 'd'})
 print(pickle.loads(pick))
 
-file_obj = StringIO.StringIO()
+file_obj = io.BytesIO()
 pickle.dump([1, 2, '3'], file_obj)
 file_obj.seek(0)
 print(pickle.load(file_obj))
 
 file_obj.seek(0)
 print(pickle.Unpickler(file_obj).load())
-
-# cPickle
-serialized = cPickle.dumps({(): []})
-print(cPickle.loads(serialized))
-
-file_obj = StringIO.StringIO()
-cPickle.dump((1,), file_obj)
-file_obj.seek(0)
-print(cPickle.load(file_obj))
-
-file_obj.seek(0)
-print(cPickle.Unpickler(file_obj).load())
-
diff --git a/examples/ssl-insecure-version.py b/examples/ssl-insecure-version.py
index bd6f659..80d6e48 100644
--- a/examples/ssl-insecure-version.py
+++ b/examples/ssl-insecure-version.py
@@ -20,6 +20,13 @@ herp_derp(ssl_version=ssl.PROTOCOL_TLSv1)
 herp_derp(method=SSL.SSLv3_METHOD)
 herp_derp(method=SSL.TLSv1_METHOD)
 
+ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_1)
+SSL.Context(method=SSL.TLSv1_1_METHOD)
+
+herp_derp(ssl_version=ssl.PROTOCOL_TLSv1_1)
+herp_derp(method=SSL.TLSv1_1_METHOD)
+
+
 ssl.wrap_socket()
 
 def open_ssl_socket(version=ssl.PROTOCOL_SSLv2):
@@ -31,6 +38,9 @@ def open_ssl_socket(version=SSL.SSLv2_METHOD):
 def open_ssl_socket(version=SSL.SSLv23_METHOD):
     pass
 
-# this one will pass ok
 def open_ssl_socket(version=SSL.TLSv1_1_METHOD):
     pass
+
+# this one will pass ok
+def open_ssl_socket(version=SSL.TLSv1_2_METHOD):
+    pass
diff --git a/examples/tarfile_extractall.py b/examples/tarfile_extractall.py
new file mode 100644
index 0000000..2af3eb5
--- /dev/null
+++ b/examples/tarfile_extractall.py
@@ -0,0 +1,47 @@
+import sys
+import tarfile
+import tempfile
+
+
+def unsafe_archive_handler(filename):
+    tar = tarfile.open(filename)
+    tar.extractall(path=tempfile.mkdtemp())
+    tar.close()
+
+
+def managed_members_archive_handler(filename):
+    tar = tarfile.open(filename)
+    tar.extractall(path=tempfile.mkdtemp(), members=members_filter(tar))
+    tar.close()
+
+
+def list_members_archive_handler(filename):
+    tar = tarfile.open(filename)
+    tar.extractall(path=tempfile.mkdtemp(), members=[])
+    tar.close()
+
+
+def provided_members_archive_handler(filename):
+    tar = tarfile.open(filename)
+    tarfile.extractall(path=tempfile.mkdtemp(), members=tar)
+    tar.close()
+
+
+def members_filter(tarfile):
+    result = []
+    for member in tarfile.getmembers():
+        if '../' in member.name:
+            print('Member name container directory traversal sequence')
+            continue
+        elif (member.issym() or member.islnk()) and ('../' in member.linkname):
+            print('Symlink to external resource')
+            continue
+        result.append(member)
+    return result
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 1:
+        filename = sys.argv[1]
+        unsafe_archive_handler(filename)
+        managed_members_archive_handler(filename)
diff --git a/examples/weak_cryptographic_key_sizes.py b/examples/weak_cryptographic_key_sizes.py
index f2443b5..357a71e 100644
--- a/examples/weak_cryptographic_key_sizes.py
+++ b/examples/weak_cryptographic_key_sizes.py
@@ -64,3 +64,9 @@ pycryptodomex_rsa.generate(512)
 rsa.generate_private_key(public_exponent=65537,
                          key_size=some_key_size,
                          backend=backends.default_backend())
+
+# Can't reliably know which curve was passed, in some cases like below
+ec.generate_private_key(
+    curve=curves[self.curve]['create'](self.size),
+    backend=backends.default_backend()
+)
diff --git a/examples/yaml_load.py b/examples/yaml_load.py
index 21d8797..a6a2eb1 100644
--- a/examples/yaml_load.py
+++ b/examples/yaml_load.py
@@ -1,5 +1,7 @@
 import json
 import yaml
+from yaml import CSafeLoader
+from yaml import SafeLoader
 
 
 def test_yaml_load():
@@ -18,3 +20,9 @@ def test_json_load():
     j = json.load("{}")
 
 yaml.load("{}", Loader=yaml.Loader)
+
+# no issue should be found
+yaml.load("{}", SafeLoader)
+yaml.load("{}", yaml.SafeLoader)
+yaml.load("{}", CSafeLoader)
+yaml.load("{}", yaml.CSafeLoader)
diff --git a/setup.cfg b/setup.cfg
index 66f6b68..dcf8663 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -140,6 +140,9 @@ bandit.plugins =
     # bandit/plugins/logging_config_insecure_listen.py
     logging_config_insecure_listen = bandit.plugins.logging_config_insecure_listen:logging_config_insecure_listen
 
+    #bandit/plugins/tarfile_unsafe_members.py
+    tarfile_unsafe_members = bandit.plugins.tarfile_unsafe_members:tarfile_unsafe_members
+
 [build_sphinx]
 all_files = 1
 build-dir = doc/build


Test patch:
diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py
index 2005d1e..4c115fa 100644
--- a/tests/functional/test_functional.py
+++ b/tests/functional/test_functional.py
@@ -300,8 +300,8 @@ class FunctionalTests(testtools.TestCase):
     def test_os_chmod(self):
         """Test setting file permissions."""
         expect = {
-            "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 2, "HIGH": 8},
-            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 9},
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 4, "HIGH": 8},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 11},
         }
         self.check_example("os-chmod.py", expect)
 
@@ -348,16 +348,16 @@ class FunctionalTests(testtools.TestCase):
     def test_pickle(self):
         """Test for the `pickle` module."""
         expect = {
-            "SEVERITY": {"UNDEFINED": 0, "LOW": 2, "MEDIUM": 6, "HIGH": 0},
-            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 8},
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 3, "HIGH": 0},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 4},
         }
         self.check_example("pickle_deserialize.py", expect)
 
     def test_dill(self):
         """Test for the `dill` module."""
         expect = {
-            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 2, "HIGH": 0},
-            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3},
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 3, "HIGH": 0},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 4},
         }
         self.check_example("dill.py", expect)
 
@@ -377,6 +377,14 @@ class FunctionalTests(testtools.TestCase):
         }
         self.check_example("jsonpickle.py", expect)
 
+    def test_pandas_read_pickle(self):
+        """Test for the `pandas.read_pickle` module."""
+        expect = {
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 1, "HIGH": 0},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 2},
+        }
+        self.check_example("pandas_read_pickle.py", expect)
+
     def test_popen_wrappers(self):
         """Test the `popen2` and `commands` modules."""
         expect = {
@@ -446,12 +454,8 @@ class FunctionalTests(testtools.TestCase):
     def test_ssl_insecure_version(self):
         """Test for insecure SSL protocol versions."""
         expect = {
-            "SEVERITY": {"LOW": 1, "MEDIUM": 10, "HIGH": 7},
-            "CONFIDENCE": {"LOW": 0, "MEDIUM": 11, "HIGH": 7},
-        }
-        expect = {
-            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 10, "HIGH": 7},
-            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 11, "HIGH": 7},
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 13, "HIGH": 9},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 14, "HIGH": 9},
         }
         self.check_example("ssl-insecure-version.py", expect)
 
@@ -896,3 +900,11 @@ class FunctionalTests(testtools.TestCase):
             "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 3},
         }
         self.check_example("snmp.py", expect)
+
+    def test_tarfile_unsafe_members(self):
+        """Test insecure usage of tarfile."""
+        expect = {
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 2, "HIGH": 1},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 2, "HIGH": 1},
+        }
+        self.check_example("tarfile_extractall.py", expect)