Skip to content

Commit 0136edf

Browse files
dwiley258BartKaras1128s19110myteron
authored
adding CWE-459 (#893)
Adding documentation to CWE-459 as part of #531 * Update docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-459/ * fixed linting errors --------- Signed-off-by: ewlxdnx <[email protected]> Signed-off-by: dwiley258 <[email protected]> Signed-off-by: Helge Wehder <[email protected]> Co-authored-by: Bartlomiej Karas <[email protected]> Co-authored-by: Hubert Daniszewski <[email protected]> Co-authored-by: Helge Wehder <[email protected]> Co-authored-by: Bartlomiej Karas <[email protected]>
1 parent 9bdc36e commit 0136edf

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# CWE-459: Incomplete Cleanup
2+
3+
Leftover temporary files not properly cleaned up after the completion of any script, can lead to resource exhaustion and disable a service.
4+
5+
Temporary files can be used to store data, either between processes, or to preserve memory. Using temporary files comes with several challenges, we need to ensure that the temporary files are removed before the termination of the process. In the case of the process terminating abnormally, we can't rely on a finally block as it could fail to run. In the case that the program still fails to free up the execution, we need to ensure that the temporary files are created with the correct permissions and in the correct location so the OS can cleanup after the process finishes, while ensuring to restrict access to other processes.
6+
7+
In Python there is two documented ways to create temporary files using the `tempfile` library, `tempfile.mkstemp()` and `tempfile.NamedTemporaryFile()`.
8+
9+
`tempfile.mkstemp()` creates a secure file in the most secure fashion allowing only read and write to the user who executed the python script. The function returns a tuple containing a file descriptor and the file path, but since this tuple is not a context manager, it does not directly integrate with the `with` statement, which automatically manages resource cleanup. This means that the user is responsible for deleting the temporary file after use.
10+
11+
`tempfile.NamedTemporaryFile()` is more advanced than the `mkstemp()` method as it returns a file-like object, which acts as a context manager, which works well with the `with` statement, although it creates the file with the same permissions as `mkstemp()`. The default behaviour is to delete the file once the `with` block is finished. If the file is needed outside of the with block, the `delete_on_close parameter` must be set to `false`.
12+
13+
## Non-Compliant Code Example
14+
15+
In the `noncompliant01.py` example, a temporary file is created but is not removed after completion.
16+
17+
*[noncompliant01.py](noncompliant01.py):*
18+
19+
```python
20+
# SPDX-FileCopyrightText: OpenSSF project contributors
21+
# SPDX-License-Identifier: MIT
22+
""" Non-compliant Code Example """
23+
f = open("tempfile.txt", "w")
24+
f.write("temporary file created!")
25+
f.close()
26+
```
27+
28+
In `noncompliant02.py`, we are using the `mkstemp` method to generate the temporary file. This will create a more secure temporary file but doesn't do clean-up of the file after the end of execution.
29+
30+
*[noncompliant02.py](noncompliant02.py):*
31+
32+
```python
33+
# SPDX-FileCopyrightText: OpenSSF project contributors
34+
# SPDX-License-Identifier: MIT
35+
""" Non-compliant Code Example """
36+
import os
37+
from tempfile import mkstemp
38+
39+
fd, path = mkstemp()
40+
with os.fdopen(fd, 'w') as f:
41+
f.write('TEST\n')
42+
43+
print(path)
44+
```
45+
46+
Neither of the code examples removes the file after use, leaving cleanup to the user or the operating system.
47+
48+
## Compliant Solution
49+
50+
In `compliant01.py` we use the `tempfile` module to generate our temporary file. When not passing in `delete=false` the default behaviour is the file will be deleted after the corresponding file-like objects are closed.
51+
52+
Thanks to the use of the `with` statement we ensure that the file is closed after writing to it, even if an error is to occur.
53+
54+
*[compliant01.py](compliant01.py):*
55+
56+
```python
57+
"""Compliant Code Example"""
58+
59+
# SPDX-FileCopyrightText: OpenSSF project contributors
60+
# SPDX-License-Identifier: MIT
61+
""" Compliant Code Example """
62+
import tempfile
63+
64+
with tempfile.NamedTemporaryFile() as temp_file:
65+
temp_file.write(b'This temporary file will be deleted.')
66+
temp_file_path = temp_file.name
67+
68+
with open(temp_file_path, 'rb') as temp_file:
69+
print(temp_file.read())
70+
```
71+
72+
In the first `with` block of `compliant01.py`, a temporary file is created, which will be automatically deleted once the block is exited. It is expected that the second `with` block will return a `FileNotFoundError` as the file will have been successfully deleted.
73+
74+
## Automated Detection
75+
76+
|Tool|Version|Checker|Description|
77+
|:---|:---|:---|:---|
78+
|Pylint|3.3.7 on python 3.10.4|[W1514:unspecified-encoding](https://pylint.readthedocs.io/en/latest/user_guide/messages/warning/unspecified-encoding.html)|Using open without explicitly specifying an encoding|
79+
80+
## Related Guidelines
81+
82+
|||
83+
|:---|:---|
84+
|[MITRE CWE](http://cwe.mitre.org/)|Pillar: [CWE-664: Improper Control of a Resource Through its Lifetime (mitre.org)](https://cwe.mitre.org/data/definitions/664.html)|
85+
|[MITRE CWE](http://cwe.mitre.org/)|Base: [CWE-459: Incomplete Cleanup](https://cwe.mitre.org/data/definitions/459.html)|
86+
|[SEI CERT Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[FIO03-J. Remove temporary files before termination](https://wiki.sei.cmu.edu/confluence/display/java/FIO03-J.+Remove+temporary+files+before+termination)|
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Compliant Code Example """
4+
import tempfile
5+
6+
with tempfile.NamedTemporaryFile() as temp_file:
7+
temp_file.write(b'This temporary file will be deleted.')
8+
temp_file_path = temp_file.name
9+
10+
with open(temp_file_path, 'rb') as temp_file:
11+
print(temp_file.read())
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Non-compliant Code Example """
4+
f = open("tempfile.txt", "w")
5+
f.write("temporary file created!")
6+
f.close()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
""" Non-compliant Code Example """
4+
import os
5+
from tempfile import mkstemp
6+
7+
fd, path = mkstemp()
8+
with os.fdopen(fd, 'w') as f:
9+
f.write('TEST\n')
10+
11+
print(path)

0 commit comments

Comments
 (0)