diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/README.md new file mode 100755 index 00000000..1ee26926 --- /dev/null +++ b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/README.md @@ -0,0 +1,141 @@ +# CWE-252: Unchecked Return Value + +Return values of methods and functions should always be checked to ensure operations have been performed correctly. + +When immutable objects are used, methods that aim to modify them have to create a new object with the desired changed and return it. For the results of such methods to take place, the developer must remember to assign the new value to a variable, otherwise it won't be accessible. They can also be used to handle unexpected behaviors by returning specific values (such as `None` or a other default values) that may require additional safety checks. + +## Non-Compliant Code Example - Immutable objects + +This non-compliant code example shows a common mistake when trying to update an immutable object. Since `str` is an immutable type, `str.replace()` creates a new `str` object with the desired change [[Python Docs - str.replace](https://docs.python.org/3.9/library/stdtypes.html#str.replace)]. This object must be then assigned, typically in place of the original string. If not, the new value remains unused. + +*[noncompliant01.py](noncompliant01.py):* + +```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Non-compliant Code Example """ + + +def silly_string(user_input): + """Function that changes the content of a string""" + user_input.replace("un", "very ") + return user_input + + +##################### +# exploiting above code example +##################### +print(silly_string("unsafe string")) + +``` + +Despite calling `silly_string()`, "unsafe string" is printed instead of the expected "very safe string" as the return value of `str.replace()` has been ignored. + +## Compliant Solution - Immutable objects + +This compliant solution correctly returns the value from `str.replace()` and then prints it: + +*[compliant01.py](compliant01.py):* + +```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Compliant Code Example """ + + +def silly_string(user_input): + """Function that changes the content of a string""" + return user_input.replace("un", "very ") + + +##################### +# exploiting above code example +##################### +print(silly_string("unsafe string")) + +``` + +## Non-Compliant Code Example - Invalid value handling + +Return values are also important when they may be used as an alternative to raising exceptions. `str.find()`, unlike `str.index()` returns -1 [[Python Docs - str.find](https://docs.python.org/3/library/stdtypes.html#str.find)] instead of raising a `ValueError` [[Python Docs - str.index](https://docs.python.org/3/library/stdtypes.html#str.index)] when it cannot find the given sub-string. +This non-compliant code example shows that using this value will point to the last element of the string regardless of what it is. + +*[noncompliant02.py](noncompliant02.py):* + +```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Non-compliant Code Example """ + + +def find_in_string(full_string, sub_string): + """Function that searches for a sub-string in a given string""" + index = full_string.find(sub_string) + print(f"Sub-string '{sub_string}' appears in '{full_string}' at index {index}'") + + +##################### +# exploiting above code example +##################### +my_string = "Secure Python coding" +find_in_string(my_string, "Python") +find_in_string(my_string, "I'm evil") + +``` + +Even though `I'm evil` is clearly not a part of "Secure Python coding", the `find_in_string()` method will suggest otherwise. + +## Compliant Solution - Invalid value handling + +Since `str.find()` indicates the fact that the sub-string couldn't be found with a negative index, a simple `if` check is enough to tackle the issue from the previous code example. + +*[compliant02.py](compliant02.py):* + +```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Non-compliant Code Example """ + + +def find_in_string(full_string, sub_string): + """Function that searches for a sub-string in a given string""" + index = full_string.find(sub_string) + if index >= 0: + print(f"Sub-string '{sub_string}' appears in '{full_string}' at index {index}'") + else: + print(f"There is no '{sub_string}' in '{full_string}'") + + +##################### +# exploiting above code example +##################### +my_string = "Secure Python coding" +find_in_string(my_string, "Python") +find_in_string(my_string, "I'm evil") + +``` + +Now, the latter print will correctly indicate the lack of `I'm evil` in `Secure Python coding`. + +## Automated Detection + +|Tool|Version|Checker|Description| +|:---|:---|:---|:---| +|Bandit|1.7.4 on Python 3.10.4|Not Available|| +|Flake8|8-4.0.1 on Python 3.10.4|Not Available|| + +## Related Guidelines + +||| +|:---|:---| +|[MITRE CWE](http://cwe.mitre.org/)|Pillar: [CWE-703: Improper Check or Handling of Exceptional Conditions (4.13) (mitre.org)](https://cwe.mitre.org/data/definitions/703.html)| +|[MITRE CWE](http://cwe.mitre.org/)|Base: [CWE-252: Unchecked Return Value](https://cwe.mitre.org/data/definitions/252.html)| +|[SEI CERT Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[EXP00-J. Do not ignore values returned by methods](https://wiki.sei.cmu.edu/confluence/display/java/EXP00-J.+Do+not+ignore+values+returned+by+methods)| +|[SEI CERT C Coding Standard](https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard)|[EXP12-C. Do not ignore values returned by functions](https://wiki.sei.cmu.edu/confluence/display/c/EXP12-C.+Do+not+ignore+values+returned+by+functions)| +|ISO/IEC TR 24772:2019|Passing Parameters and Return Values \[CSJ\]| + +## Bibliography + +||| +|:---|:---| +|[[Python Docs - str.replace](https://docs.python.org/3.9/library/stdtypes.html#str.replace)]
[[Python Docs - str.find](https://docs.python.org/3/library/stdtypes.html#str.find)]
[[Python Docs - str.index](https://docs.python.org/3/library/stdtypes.html#str.index)]|Python Software Foundation. (2025). Built-in Types [online]. Available from: [https://docs.python.org/3.9/library/stdtypes.html](https://docs.python.org/3.9/library/stdtypes.html) \[accessed 17 June 2025\] | diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/compliant01.py b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/compliant01.py new file mode 100644 index 00000000..d8ab1422 --- /dev/null +++ b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/compliant01.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Compliant Code Example """ + + +def silly_string(user_input): + """Function that changes the content of a string""" + return user_input.replace("un", "very ") + + +##################### +# exploiting above code example +##################### +print(silly_string("unsafe string")) diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/compliant02.py b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/compliant02.py new file mode 100644 index 00000000..6c76a685 --- /dev/null +++ b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/compliant02.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Non-compliant Code Example """ + + +def find_in_string(full_string, sub_string): + """Function that searches for a sub-string in a given string""" + index = full_string.find(sub_string) + if index >= 0: + print(f"Sub-string '{sub_string}' appears in '{full_string}' at index {index}'") + else: + print(f"There is no '{sub_string}' in '{full_string}'") + + +##################### +# exploiting above code example +##################### +my_string = "Secure Python coding" +find_in_string(my_string, "Python") +find_in_string(my_string, "I'm evil") diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/noncompliant01.py b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/noncompliant01.py new file mode 100644 index 00000000..c450a557 --- /dev/null +++ b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/noncompliant01.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Non-compliant Code Example """ + + +def silly_string(user_input): + """Function that changes the content of a string""" + user_input.replace("un", "very ") + return user_input + + +##################### +# exploiting above code example +##################### +print(silly_string("unsafe string")) diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/noncompliant02.py b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/noncompliant02.py new file mode 100644 index 00000000..56654b8f --- /dev/null +++ b/docs/Secure-Coding-Guide-for-Python/CWE-703/CWE-252/noncompliant02.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +""" Non-compliant Code Example """ + + +def find_in_string(full_string, sub_string): + """Function that searches for a sub-string in a given string""" + index = full_string.find(sub_string) + print(f"Sub-string '{sub_string}' appears in '{full_string}' at index {index}'") + + +##################### +# exploiting above code example +##################### +my_string = "Secure Python coding" +find_in_string(my_string, "Python") +find_in_string(my_string, "I'm evil") diff --git a/docs/Secure-Coding-Guide-for-Python/readme.md b/docs/Secure-Coding-Guide-for-Python/readme.md index 445c02db..1999e391 100644 --- a/docs/Secure-Coding-Guide-for-Python/readme.md +++ b/docs/Secure-Coding-Guide-for-Python/readme.md @@ -55,6 +55,7 @@ It is __not production code__ and requires code-style or python best practices t |[CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)](CWE-664/CWE-409/.)|| |[CWE-410: Insufficient Resource Pool](CWE-664/CWE-410/README.md)|| |[CWE-426: Untrusted Search Path](CWE-664/CWE-426/README.md)|[CVE-2015-1326](https://www.cvedetails.com/cve/CVE-2015-1326),
CVSSv3.0: __8.8__,
EPSS: __00.20__ (23.11.2023)| +|[CWE-459: Incomplete Cleanup](CWE-664/CWE-459/README.md)|| |[CWE-501: Trust Boundary Violation)](CWE-664/CWE-501/README.md)|[CVE-2023-28597](https://www.cvedetails.com/cve/CVE-2023-28597),
CVSSv3.0: __7.5__,
EPSS: __00.11__ (05.11.2024)| |[CWE-502: Deserialization of Untrusted Data)](CWE-664/CWE-502/.)|[CVE-2018-8021](https://www.cvedetails.com/cve/CVE-2018-8021),
CVSSv3.0: __9.8__,
EPSS: __93.54__ (05.11.2024)| |[CWE-532: Insertion of Sensitive Information into Log File](CWE-664/CWE-532/README.md)|[CVE-2023-45585](https://www.cvedetails.com/cve/CVE-2023-45585),
CVSSv3.1: __9.8__,
EPSS: __0.04__ (01.11.2024)| @@ -85,13 +86,14 @@ It is __not production code__ and requires code-style or python best practices t |[CWE-778: Insufficient Logging](CWE-693/CWE-778/README.md)|| |[CWE-798: Use of hardcoded credentials](CWE-693/CWE-798/README.md)|| -|[CWE-697: Incorrect Comparison](https://cwe.mitre.org/data/definitions/703.html)|Prominent CVE| +|[CWE-697: Incorrect Comparison](https://cwe.mitre.org/data/definitions/697.html)|Prominent CVE| |:----------------------------------------------------------------|:----| |[CWE-595: Comparison of Object References Instead of Object Contents](CWE-697/CWE-595/README.md)|| |[CWE-703: Improper Check or Handling of Exceptional Conditions](https://cwe.mitre.org/data/definitions/703.html)|Prominent CVE| |:----------------------------------------------------------------|:----| |[CWE-230: Improper Handling of Missing Values](CWE-703/CWE-230/.)|| +|[CWE-252: Unchecked Return Value](CWE-703/CWE-252/README.md)|| |[CWE-390: Detection of Error Condition without Action](CWE-703/CWE-390/README.md)|| |[CWE-392: Missing Report of Error Condition](CWE-703/CWE-392/README.md)|| |[CWE-754: Improper Check for Unusual or Exceptional Conditions - float](CWE-703/CWE-754/README.md)||