mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
Merge pull request #785 from taus-semmle/python-unsafe-use-of-mktemp
Python: Add query for unsafe use of `tempfile.mktemp`.
This commit is contained in:
7
python/ql/src/Security/CWE-377/InsecureTemporaryFile.py
Normal file
7
python/ql/src/Security/CWE-377/InsecureTemporaryFile.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from tempfile import mktemp
|
||||
|
||||
def write_results(results):
|
||||
filename = mktemp()
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
52
python/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp
Normal file
52
python/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Functions that create temporary file names (such as <code>tempfile.mktemp</code>
|
||||
and <code>os.tempnam</code>) are fundamentally insecure, as they do not
|
||||
ensure exclusive access to a file with the temporary name they return.
|
||||
The file name returned by these functions is guaranteed to be unique on
|
||||
creation but the file must be opened in a separate operation. There is no
|
||||
guarantee that the creation and open operations will happen atomically. This
|
||||
provides an opportunity for an attacker to interfere with the file before it is
|
||||
opened.
|
||||
</p>
|
||||
<p>
|
||||
Note that <code>mktemp</code> has been deprecated since Python 2.3.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Replace the use of <code>mktemp</code> with some of the more secure functions
|
||||
in the <code>tempfile</code> module, such as <code>TemporaryFile</code>. If the
|
||||
file is intended to be accessed from other processes, consider using the
|
||||
<code>NamedTemporaryFile</code> function.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following piece of code opens a temporary file and writes a set of results
|
||||
to it. Because the file name is created using <code>mktemp</code>, another
|
||||
process may access this file before it is opened using <code>open</code>.
|
||||
</p>
|
||||
<sample src="InsecureTemporaryFile.py" />
|
||||
|
||||
<p>
|
||||
By changing the code to use <code>NamedTemporaryFile</code> instead, the file is
|
||||
opened immediately.
|
||||
</p>
|
||||
<sample src="SecureTemporaryFile.py" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li>
|
||||
Python Standard Library: <a href="https://docs.python.org/3/library/tempfile.html#tempfile.mktemp">tempfile.mktemp</a>.
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
31
python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql
Normal file
31
python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @name Insecure temporary file
|
||||
* @description Creating a temporary file using this method may be insecure.
|
||||
* @id py/insecure-temporary-file
|
||||
* @problem.severity error
|
||||
* @sub-severity high
|
||||
* @precision high
|
||||
* @tags external/cwe/cwe-377
|
||||
* security
|
||||
*/
|
||||
|
||||
import python
|
||||
|
||||
FunctionObject temporary_name_function(string mod, string function) {
|
||||
(
|
||||
mod = "tempfile" and function = "mktemp"
|
||||
or
|
||||
mod = "os" and
|
||||
(
|
||||
function = "tmpnam"
|
||||
or
|
||||
function = "tempnam"
|
||||
)
|
||||
) and
|
||||
result = any(ModuleObject m | m.getName() = mod).getAttribute(function)
|
||||
}
|
||||
|
||||
from Call c, string mod, string function
|
||||
where
|
||||
temporary_name_function(mod, function).getACall().getNode() = c
|
||||
select c, "Call to deprecated function " + mod + "." + function + " may be insecure."
|
||||
6
python/ql/src/Security/CWE-377/SecureTemporaryFile.py
Normal file
6
python/ql/src/Security/CWE-377/SecureTemporaryFile.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
def write_results(results):
|
||||
with NamedTemporaryFile(mode="w+", delete=False) as f:
|
||||
f.write(results)
|
||||
print("Results written to", f.name)
|
||||
@@ -0,0 +1,3 @@
|
||||
| InsecureTemporaryFile.py:5:16:5:23 | mktemp() | Call to deprecated function tempfile.mktemp may be insecure. |
|
||||
| InsecureTemporaryFile.py:11:16:11:27 | Attribute() | Call to deprecated function os.tempnam may be insecure. |
|
||||
| InsecureTemporaryFile.py:17:16:17:26 | Attribute() | Call to deprecated function os.tmpnam may be insecure. |
|
||||
@@ -0,0 +1,20 @@
|
||||
from tempfile import mktemp
|
||||
import os
|
||||
|
||||
def write_results1(results):
|
||||
filename = mktemp()
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
|
||||
def write_results2(results):
|
||||
filename = os.tempnam()
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
|
||||
def write_results3(results):
|
||||
filename = os.tmpnam()
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-377/InsecureTemporaryFile.ql
|
||||
@@ -0,0 +1,6 @@
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
def write_results(results):
|
||||
with NamedTemporaryFile(mode="w+", delete=False) as f:
|
||||
f.write(results)
|
||||
print("Results written to", f.name)
|
||||
2
python/ql/test/query-tests/Security/CWE-377/options
Normal file
2
python/ql/test/query-tests/Security/CWE-377/options
Normal file
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: -p ../lib/ --max-import-depth=3
|
||||
optimize: true
|
||||
@@ -9,3 +9,9 @@ def chmod(path, mode):
|
||||
|
||||
def open(path, flags, mode):
|
||||
pass
|
||||
|
||||
def tempnam(*args):
|
||||
pass
|
||||
|
||||
def tmpnam(*args):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user