Skip to content

Commit 09cd05b

Browse files
BartyBoi1128BartKaras1128myterons19110
authored
CWE-390: Detection of Error Condition without Action (#805)
* Adding doc for CWE-390: Detection of Error Condition without Action as part of #831 Signed-off-by: Helge Wehder <[email protected]> * Removed Bloch and Goetz from bibliography Signed-off-by: BartyBoi1128 <[email protected]> * Added new "Example Code Example" section and put it after Exceptions. I thought this order made more sense than before, will discuss with Helge Signed-off-by: BartyBoi1128 <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-390/REAME.md Should have been "in use" rather than "on use" Co-authored-by: Hubert Daniszewski <[email protected]> Signed-off-by: BartyBoi1128 <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-390/REAME.md Surrounding "except" in backticks Co-authored-by: Hubert Daniszewski <[email protected]> Signed-off-by: BartyBoi1128 <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-390/REAME.md Capitalizing "CTRL+C" to stay consistent Co-authored-by: Hubert Daniszewski <[email protected]> Signed-off-by: BartyBoi1128 <[email protected]> * Update docs/Secure-Coding-Guide-for-Python/C Co-authored-by: Hubert Daniszewski <61824500+ --------- Signed-off-by: ebakrra <[email protected]> Signed-off-by: BartyBoi1128 <[email protected]> Signed-off-by: myteron <[email protected]> Co-authored-by: ebakrra <[email protected]> Co-authored-by: Helge Wehder <[email protected]> Co-authored-by: Hubert Daniszewski <[email protected]>
1 parent 1542b74 commit 09cd05b

File tree

4 files changed

+179
-50
lines changed

4 files changed

+179
-50
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# CWE-390: Detection of Error Condition without Action
2+
3+
Allow exceptions to bubble up and handle exceptions at the right level in the stack.
4+
5+
Each `except` block must ensure that the program continues only with formally specified behavior by either:
6+
7+
* Recovering from the exceptional condition
8+
* Re-throwing the exception with additional information
9+
* Throwing custom exception only if it provides a benefit over Python's [Built-in Exceptions](https://docs.python.org/3.9/library/exceptions.html) [Python.org 2022].
10+
11+
Invalid reasons for suppressing exceptions cause:
12+
13+
* Excessive complexity
14+
* Print statements from lower levels
15+
* Incomplete trace-logs
16+
* Excessive logging
17+
18+
Printing the stack trace can reveal details and sensitive data about an application such as the components in use, existing users, and other sensitive information such as keys or passwords, as described in [CWE-209: Generation of Error Message Containing Sensitive Information](https://cwe.mitre.org/data/definitions/209.html) and will not be handled in these examples.
19+
20+
## Non-Compliant Code Example - Bare Exception
21+
22+
In Python `Exception` extends from `BaseException`and a bare `except` will catch everything.
23+
24+
For instance, catching a bare `except` causes a user to be unable to stop a script via `CTRL+C`, due to the base `except` catching all exceptions. In comparison, catching `except Exception` allows a `KeyboardInterrupt` to be the Python interpreter itself or other parts of the code. This is due to `KeyboardInterrupt` extending `BaseException` and not `Exception`.
25+
26+
Note that using `except Exception` is still too broad as per [CWE-755: Improper Handling of Exceptional Conditions](https://github.com/ossf/wg-best-practices-os-developers/blob/main/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-755/README.md) and that a more specific exception handling is preferred.
27+
28+
The `noncompliant01.py` code demonstrates a bare `except` on a `ZeroDivisionError` and must be run on the command line in order to experience the issue.
29+
30+
*[noncompliant01.py](noncompliant01.py):*
31+
32+
```py
33+
# SPDX-FileCopyrightText: OpenSSF project contributors
34+
# SPDX-License-Identifier: MIT
35+
""" Non-compliant Code Example """
36+
37+
from time import sleep
38+
39+
40+
def exception_example():
41+
"""Non-compliant Code Example using bare except"""
42+
while True:
43+
try:
44+
sleep(1)
45+
_ = 1 / 0
46+
except:
47+
print("Don't care")
48+
49+
50+
#####################
51+
# exploiting above code example
52+
#####################
53+
exception_example()
54+
```
55+
56+
The `noncompliant01.py` will continue to run when launched via terminal even when using `CTRL+C`.
57+
58+
The process will have to be terminated or killed in order to stop it. A programming IDE will allow stopping the `noncompliant01.py`as IDEs tend to kill the process rather than sending `CTRL+C`.
59+
60+
## Compliant Code Example - Bare Exception
61+
62+
The `compliant01.py` code example can be stopped via `CTRL+C` on the command line as it is catching the self created `ZeroDivisionError` instead of using a bare exception.
63+
64+
*[compliant01.py](compliant01.py):*
65+
66+
```py
67+
# SPDX-FileCopyrightText: OpenSSF project contributors
68+
# SPDX-License-Identifier: MIT
69+
""" Compliant Code Example """
70+
from time import sleep
71+
72+
73+
def exception_example():
74+
"""Compliant Code Example catching a specific exception"""
75+
while True:
76+
sleep(1)
77+
try:
78+
_ = 1 / 0
79+
except ZeroDivisionError:
80+
print("How is it now?")
81+
82+
83+
#####################
84+
# exploiting above code example
85+
#####################
86+
exception_example()
87+
```
88+
89+
If recovery from an exception remains impossible, it is often best practice to wrap the checked exception in an unchecked exception and rethrow it. This approach allows the application to fail gracefully or log the error for future debugging, rather than crashing unexpectedly.
90+
91+
`example01.py` assist in the understanding of Java's SEI Cert exceptions [SEI CERT ERR00-J 2025](https://wiki.sei.cmu.edu/confluence/display/java/ERR00-J.+Do+not+suppress+or+ignore+checked+exceptions) by providing a use-case specfic explaination `slice_cake:You got to give me plates` when re-throwing `ZeroDivisionError`.
92+
93+
*[example01.py](example01.py):*
94+
95+
```py
96+
# SPDX-FileCopyrightText: OpenSSF project contributors
97+
# SPDX-License-Identifier: MIT
98+
"""Code Example"""
99+
100+
101+
def slice_cake(cake: int, plates: int) -> float:
102+
"""Calculates size of each slice per plate for a cake
103+
Args:
104+
cake (int) : Size of the cake
105+
guests (int): Amount of guests
106+
Returns:
107+
(float): Size of each slice
108+
"""
109+
110+
try:
111+
return cake / plates
112+
except ZeroDivisionError as zero_division_error:
113+
raise ZeroDivisionError(
114+
"slice_cake:You got to give me plates"
115+
) from zero_division_error
116+
117+
118+
#####################
119+
# exploiting above code example
120+
#####################
121+
slice_cake(cake=100, plates=0)
122+
```
123+
124+
## Exceptions
125+
126+
The following two exceptions, highlighted in [SEI Cert's Oracle Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java), are important to understand when to attempt to handle exceptions at the right level in the stack in Python also.
127+
128+
* __ERR00-J-EX0:__ You may suppress exceptions during the release of non-reusable resources, such as closing files, network sockets, or shutting down threads, if they don't affect future program behavior.
129+
* __ERR00-J-EX1:__ Allow higher-level code to catch and attempt recovery from exceptions. If recovery is not possible, log the exception, add information if needed, and rethrow it.
130+
131+
## Automated Detection
132+
133+
|Tool|Version|Checker|Description|
134+
|:----|:----|:----|:----|
135+
|[Ruff](https://docs.astral.sh/ruff/)|v0.4.5|[bare-except (E722)](https://docs.astral.sh/ruff/rules/bare-except/)|Use lazy % formatting in logging functions|
136+
|[Pylint](https://pylint.pycqa.org/)|3.2.7|[W0702:bare-except](https://pylint.pycqa.org/en/latest/user_guide/messages/warning/bare-except.html)|No exception type(s) specified|
137+
|[flake8](https://www.flake8rules.com/)|7.1.1|[E722](https://www.flake8rules.com/rules/E722.html)|do not use bare 'except'|
138+
139+
## Related Guidelines
140+
141+
|||
142+
|:---|:---|
143+
|[MITRE](https://github.com/ossf/wg-best-practices-os-developers/tree/main/docs/Secure-Coding-Guide-for-Python)|[CWE-209: Generation of Error Message Containing Sensitive Information](https://cwe.mitre.org/data/definitions/209.html)|
144+
|[SEI CERT Oracle Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[ERR00-J. Do not suppress or ignore checked exceptions](https://wiki.sei.cmu.edu/confluence/display/java/ERR00-J.+Do+not+suppress+or+ignore+checked+exceptions)|
145+
|[MITRE CWE Base](http://cwe.mitre.org/)|[CWE-703](https://cwe.mitre.org/data/definitions/703.html), Improper Check or Handling of Exceptional Conditions|
146+
|[MITRE CWE Pillar](http://cwe.mitre.org/)|[CWE-390](http://cwe.mitre.org/data/definitions/390.html), Detection of Error Condition without Action|
147+
148+
## Biblography
149+
150+
|||
151+
|:---|:---|
152+
|[[Python.org](https://docs.python.org/3.9/) 2022]| python.org. (2022). Built-in Exceptions [online]. Available from: [https://docs.python.org/3.9/library/exceptions.html](https://docs.python.org/3.9/library/exceptions.html) [accessed 08 February 2023]|
153+
|[SEI CERT ERR00-J 2025]|ERR00-J. Do not suppress or ignore checked exceptions [online]. Available from: [https://wiki.sei.cmu.edu/confluence/display/java/ERR00-J.+Do+not+suppress+or+ignore+checked+exceptions](https://wiki.sei.cmu.edu/confluence/display/java/ERR00-J.+Do+not+suppress+or+ignore+checked+exceptions) [Accessed Februrary 2025]|

docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-390/compliant02.py

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-FileCopyrightText: OpenSSF project contributors
2+
# SPDX-License-Identifier: MIT
3+
"""Code Example"""
4+
5+
6+
def slice_cake(cake: int, plates: int) -> float:
7+
"""Calculates size of each slice per plate for a cake
8+
Args:
9+
cake (int) : Size of the cake
10+
guests (int): Amount of guests
11+
Returns:
12+
(float): Size of each slice
13+
"""
14+
15+
try:
16+
return cake / plates
17+
except ZeroDivisionError as zero_division_error:
18+
raise ZeroDivisionError(
19+
"slice_cake:You got to give me plates"
20+
) from zero_division_error
21+
22+
23+
#####################
24+
# exploiting above code example
25+
#####################
26+
slice_cake(cake=100, plates=0)

docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-390/noncompliant02.py

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)