Repository: PyCQA/bandit
Pull request #330 (2018-07-02 23:18:53)

add os.tempnam() / os.tmpnam() to blacklist
Crikey, it's been a while...

This adds os.tempnam() / os.tmpnam() to the calls blacklist.

Per https://docs.python.org/2.7/library/os.html#os.tempnam and https://bugs.python.org/issue17880, this was left in 2.7 for legacy reasons, but use is potentially dangerous and tmpfile() is recommended instead.


Patch:
diff --git a/README.rst b/README.rst
index 65c29ee..cfc6c85 100644
--- a/README.rst
+++ b/README.rst
@@ -211,6 +211,7 @@ Usage::
       B322  input
       B323  unverified_context
       B324  hashlib_new_insecure_functions
+      B325  tempnam
       B401  import_telnetlib
       B402  import_ftplib
       B403  import_pickle
diff --git a/bandit/blacklists/calls.py b/bandit/blacklists/calls.py
index 12d5eb5..e1541e1 100644
--- a/bandit/blacklists/calls.py
+++ b/bandit/blacklists/calls.py
@@ -297,6 +297,23 @@ behavior that does not validate certificates or perform hostname checks.
 | B323 | unverified_context  | - ssl._create_unverified_context   | Medium    |
 +------+---------------------+------------------------------------+-----------+
 
+B325: tempnam
+--------------
+
+Use of os.tempnam() and os.tmpnam() is vulnerable to symlink attacks. Consider
+using tmpfile() instead.
+
+For further information:
+    https://docs.python.org/2.7/library/os.html#os.tempnam
+    https://bugs.python.org/issue17880
+
++------+---------------------+------------------------------------+-----------+
+| ID   |  Name               |  Calls                             |  Severity |
++======+=====================+====================================+===========+
+| B325 | tempnam             | - os.tempnam                       | Medium    |
+|      |                     | - os.tmpnam                        |           |
++------+---------------------+------------------------------------+-----------+
+
 """
 
 from bandit.blacklists import utils
@@ -541,4 +558,12 @@ def gen_blacklist():
         'or perform hostname checks.'
         ))
 
+    # skipped B324 (used in bandit/plugins/hashlib_new_insecure_functions.py)
+
+    sets.append(utils.build_conf_dict(
+        'tempnam', 'B325', ['os.tempnam', 'os.tmpnam'],
+        'Use of os.tempnam() and os.tmpnam() is vulnerable to symlink '
+        'attacks. Consider using tmpfile() instead.'
+        ))
+
     return {'Call': sets}
diff --git a/examples/tempnam.py b/examples/tempnam.py
new file mode 100644
index 0000000..bc92f03
--- /dev/null
+++ b/examples/tempnam.py
@@ -0,0 +1,13 @@
+from os import tempnam
+from os import tmpnam
+import os
+
+os.tmpnam()
+
+tmpnam()
+
+os.tempnam('dir1')
+os.tempnam('dir1', 'prefix1')
+
+tempnam('dir1')
+tempnam('dir1', 'prefix1')


Test patch:
diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py
index aa3d73e..820fae9 100644
--- a/tests/functional/test_functional.py
+++ b/tests/functional/test_functional.py
@@ -264,6 +264,14 @@ class FunctionalTests(testtools.TestCase):
         }
         self.check_example('mktemp.py', expect)
 
+    def test_tempnam(self):
+        '''Test for `os.tempnam` / `os.tmpnam`.'''
+        expect = {
+            'SEVERITY': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 6, 'HIGH': 0},
+            'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 0, 'HIGH': 6}
+        }
+        self.check_example('tempnam.py', expect)
+
     def test_nonsense(self):
         '''Test that a syntactically invalid module is skipped.'''
         self.run_example('nonsense.py')