diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-134/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-134/README.md index e6d4b3d7..79454c64 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-134/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-134/README.md @@ -2,7 +2,7 @@ Ensure that all format string functions are passed a static string which cannot be controlled by the user [[MITRE 2023]](https://cwe.mitre.org/data/definitions/134.html) -In Python, the use of string formatting combined with the ability to access a function's `__globals__` attribute can exposing internal variables and methods unless properly guarded. +In Python, the use of string formatting combined with the ability to access a function's `__globals__` attribute can expose internal variables and methods unless properly guarded. ## Non-Compliant Code Example diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-197/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-197/README.md index 52dee125..968a63b1 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-197/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-197/README.md @@ -126,7 +126,7 @@ while counter <= target: |Definition|Explanation|Reference| |:---|:---|:---| -|Loop Counters|loop counters are variables used to control the iterations of a loop|[Loop counter - Wikipedia](https://en.wikipedia.org/wiki/For_loop#Loop_counters)| +|Loop Counters|loop counters are variables used to control the iterations of a loop|[Loops and their control variables](http://www.knosof.co.uk/vulnerabilities/loopcntrl.pdf)| ## Automated Detection @@ -150,6 +150,6 @@ while counter <= target: ||| |:---|:---| |[IEEE Std 754-2019](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8766229)|IEEE Standard for Floating-Point Arithmetic, available from: [https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8766229](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8766229), [Last accessed June 2024] | -|[Wikipedia 2024]|Repeating Decimals, available from:[https://en.wikipedia.org/wiki/Repeating_decimal](https://en.wikipedia.org/wiki/Repeating_decimal), [Last accessed August 2024] | +|[Loops and control variables]|Derek M. Jones(2006 )Loops and their control variables, Discussion and proposed guidelines:[http://www.knosof.co.uk/vulnerabilities/loopcntrl.pdf](http://www.knosof.co.uk/vulnerabilities/loopcntrl.pdf), [Last accessed October 2025] | |[Albing and Vossen, 2017]|Albin, C. and Vossen, JP (2017) 6.13 Looping with Floating Point Values. In: Bleiel, J., Brown, K. and Head, R. eds. bash Cookbook: Solutions and Examples for bash Users, 2d Edition. Sebastopol: O'Reilly Media, Inc., pp.159-160| |[Bloch 2005]|Puzzle 34, "Down for the Count", available from: [https://web.archive.org/web/20220511061752/https://wiki.sei.cmu.edu/confluence/display/java/Rule+AA.+References#RuleAA.References-Bloch05](https://web.archive.org/web/20220511061752/https://wiki.sei.cmu.edu/confluence/display/java/Rule+AA.+References#RuleAA.References-Bloch05), [Last accessed August 2024] | diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/README.md index 03af28b5..446e7f5a 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/README.md @@ -223,8 +223,8 @@ def extract_files(filepath: str, base_path: str, exist_ok: bool = True): exist_ok (bool, optional): Overwrite existing. Defaults to True. Raises: - ZipExtractException: If there are to many files - ZipExtractException: If there are to big files + ZipExtractException: If there are too many files + ZipExtractException: If the files are too big ZipExtractException: If a directory traversal is detected """ # TODO: avoid CWE-209: Generation of Error Message Containing Sensitive Information diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/compliant01.py b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/compliant01.py index 61c2be38..6407a4fb 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/compliant01.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-409/compliant01.py @@ -43,8 +43,8 @@ def extract_files(filepath: str, base_path: str, exist_ok: bool = True): exist_ok (bool, optional): Overwrite existing. Defaults to True. Raises: - ZipExtractException: If there are to many files - ZipExtractException: If there are to big files + ZipExtractException: If there are too many files + ZipExtractException: If the files are too big ZipExtractException: If a directory traversal is detected """ # TODO: avoid CWE-209: Generation of Error Message Containing Sensitive Information diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-410/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-410/README.md index 1fe12b0d..b773f2a2 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-410/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-410/README.md @@ -1,6 +1,8 @@ # CWE-410: Insufficient Resource Pool -Ensure load control during traffic bursts or Denial of Service (DoS) by using a limited amount of threads in a pool. An attacker can cause a DoS by flooding a system with too many requests. Services with time-consuming, I/O-bound, or session-based sequential execution make limited use of available resources and can be blocked by a single hanging process or by overloading the queue. +Ensure load control during traffic bursts or Denial of Service (DoS) by using a limited amount of threads in a pool. + +An attacker can cause a DoS by flooding a system with too many requests. Services with time-consuming, I/O-bound, or session-based sequential execution make limited use of available resources and can be blocked by a single hanging process or by overloading the queue. Thread pools combine: diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-459/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-459/README.md index 4015417c..21ac6a8a 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-459/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-459/README.md @@ -54,8 +54,6 @@ Thanks to the use of the `with` statement we ensure that the file is closed afte *[compliant01.py](compliant01.py):* ```python -"""Compliant Code Example""" - # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT """ Compliant Code Example """ diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-501/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-501/README.md index 381e4fb5..aa1c5d29 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-501/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-501/README.md @@ -1,8 +1,8 @@ # CWE-501: Trust Boundary Violation -Python does not share the concept of different trust zones within the same runtime as explained in the *JAVA SEI CERT Rule 15 platform security (SEC)* [[SEI CERT 2022]](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88487683) rules. Python neither has a security manager that can control access between trusted and untrusted code running on the same JVM. “Private” instance variables that cannot be accessed except from inside an object don’t exist in Python [Python 2023]. +Python's trust boundaries rely on explicit process isolation, rather than in-process access control within a single interpreter. -In Python we need to implement different trust zone's by starting python runtime's with individual POSIX/Machine users. The POSIX/Machine user access rights must be set in accordance to level of trust per zone. +Unlike Java, where we have in-process mechanisms like [Oracle Access Management](https://docs.oracle.com/en/middleware/idm/access-manager/12.2.1.3/aiaag/introducing-oracle-access-management.html) that can enforce access boundaries inside the same runtime, standard Python does not provide a built-in in-process access manager. In Python we need to implement different trust zones by starting python runtimes with individual POSIX/Machine users. The POSIX/Machine user access rights must be set in accordance to level of trust per zone. ## Noncompliant STRIDE example - New User Sign-up Process @@ -44,6 +44,6 @@ unknown ||| |:---|:---| -|[[SEI CERT 2022]](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88487683)|Rule 15. Platform Security (SEC). Available from: [SEI CERT](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88487683) [accessed 07 May 2024]| |[[Python 2023]](https://docs.python.org/3.9/tutorial/classes.html?highlight=private#private-variables)|Python Software Foundation. (2023). Classes - Private Variables. Available from: [Python Documentation](https://docs.python.org/3.9/tutorial/classes.html?highlight=private#private-variables) [accessed 13 September 2023]| |[[OWASP, Conklin, Drake, 2023]](https://cwe.mitre.org/data/definitions/134.html)|[CWE - CWE-134: Use of Externally-Controlled Format String (4.13) (mitre.org)](https://cwe.mitre.org/data/definitions/134.html)| +|[Oracle Docs](https://docs.oracle.com/en/)| [Administering Oracle Access Management](https://docs.oracle.com/en/middleware/idm/access-manager/12.2.1.3/aiaag/introducing-oracle-access-management.html#GUID-D1D083AA-538E-4063-A921-9328DB784319) [accessed 29 October 2025]| diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-502/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-502/README.md index fafbe897..fb2e50bc 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-502/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-502/README.md @@ -1,7 +1,8 @@ # CWE-502: Deserialization of Untrusted Data +Even if data has been created from a trusted source, we need to verify that it has not been tampered with during transport. + The `pickle` module is known to be vulnerable [[docs.python.org 2023]](https://docs.python.org/3.9/library/pickle.html) against unwanted code execution during deserialization and should only be used if there is no architectural text-based alternative. -Even if data has been created from a trusted source we need to verify that it has not been tampered with during transport. Security-related concerns during object serialization and deserialization include: @@ -15,7 +16,7 @@ Security-related concerns during object serialization and deserialization includ ## Noncompliant Code Example -The `noncompliant01.py` code demonstrates arbitrary code execution [Checkoway Oct 2013] using `os.system` to launch a program during unpickling when `pickle.loads()`. +The `noncompliant01.py` code demonstrates arbitrary code execution using `os.system` to launch a program during unpickling when `pickle.loads()` [[Checkoway Oct 2013](https://checkoway.net/musings/pickle/)] *[noncompliant01.py](noncompliant01.py):* @@ -198,7 +199,7 @@ The integrity verification in `compliant01.py` throws an exception `ValueError: Text-based formats, such as `JSON` and `YAML`, should always be preferred. They have a lower set of capabilities and reduce the attack surface [python.org comparison-with-json 2023] when compared to `pickle`. -The `compliant01.py` code only allows serializing and deserialization of object data and not object methods as in `noncompliant01.py` or `compliant01.py`. +The `compliant01.py` code only allows serializing and deserialization of object data and not object methods as in `noncompliant01.py` or `example01.py`. Consider converting binary data into text using `Base64` encoding for performance and size irrelevant operations. @@ -288,7 +289,7 @@ message = None message = p3.uncan(PAYLOAD) ``` -The `compliant02.py` stops with the unpacking with a `json.decoder.JSONDecodeError`. +The `compliant01.py` stops with the unpacking with a `json.decoder.JSONDecodeError`. ## Exceptions @@ -317,6 +318,7 @@ Serialized data from a trusted input source does not require sanitization, provi |[SEI CERT Coding Standard for Java](https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java)|[SER01-J. Do not deviate from the proper signatures of serialization methods](https://wiki.sei.cmu.edu/confluence/display/java/SER01-J.+Do+not+deviate+from+the+proper+signatures+of+serialization+methods)| |[MITRE CWE](http://cwe.mitre.org/)|Pillar [CWE-664: Improper Control of a Resource Through its Lifetime (4.13) (mitre.org)](https://cwe.mitre.org/data/definitions/664.html)| |[MITRE CWE](http://cwe.mitre.org/)|Base [CWE-502, Deserialization of Untrusted Data](http://cwe.mitre.org/data/definitions/502.html)| +|[Checkoway 2013]|Checkoway, S. (2013) 'Arbitrary code execution with Python pickles', 8 October. Available from: [stephen.checkoway.com](https://stephen.checkoway.com/2013/10/08/arbitrary-code-execution-with-python-pickles/) [Accessed 07 May 2024]| ## Biblography diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/README.md index cbb7e372..064fdb91 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/README.md @@ -91,6 +91,7 @@ def do_logic(): # exploiting above code example ##################### do_logic() + ``` ## Automated Detection diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant01.py b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant01.py index d134c5f5..d500c27f 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant01.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant01.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT - """Compliant Code Example""" @@ -18,4 +17,3 @@ def do_logic(): # exploiting above code example ##################### do_logic() - diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant02.py b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant02.py index 37926ffc..71947313 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant02.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/compliant02.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT - +""" Compliant Code Example """ + + def do_logic(): try: raise Exception @@ -14,10 +16,9 @@ def do_logic(): # return statement goes here # when exception is raised conditionally return True - - + + ##################### # exploiting above code example ##################### do_logic() - diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/noncompliant01.py b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/noncompliant01.py index 3c8a2235..b681da8a 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/noncompliant01.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-584/noncompliant01.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT - """Non-compliant Code Example""" @@ -16,4 +15,3 @@ def do_logic(): # exploiting above code example ##################### do_logic() - diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-833/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-833/README.md index 20a7a741..8039d989 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-833/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-664/CWE-833/README.md @@ -1,6 +1,8 @@ # CWE-833: Deadlock -The number of threads that can simultaneously run within a `ThreadPoolExecutor` is limited by the `_max_workers` parameter. Submitting tasks whose execution is dependent on other tasks submitted to the same `ThreadPoolExecutor` may result in a *thread-starvation* deadlock. An example of this type of deadlock is shown in the following article [Brownlee, 2021], which describes it as "Deadlock 1: Submit and Wait for a Task Within a Task". Submitting a task will add it to an internal `ThreadPoolExecutor` queue. The task will be removed from the queue when one of the worker threads becomes available, i.e., after finishing its current task. If all workers are busy and all their current tasks are waiting for results from tasks that are waiting in the queue, the program will run indefinitely as no worker will be able to complete its task and take one of the blocking tasks from the queue. +Submitting tasks whose execution is dependent on other tasks submitted to the same `ThreadPoolExecutor` may result in a *thread-starvation* deadlock. + +The number of threads that can simultaneously run within a `ThreadPoolExecutor` is limited by the `_max_workers` parameter. Since `Python 3.8`, the default value for `max_workers` is `min(32, os.cpu_count() + 4)` [[Python docs]](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor). An example of this type of deadlock is shown in the following article [Brownlee, 2021], which describes it as "Deadlock 1: Submit and Wait for a Task Within a Task". Submitting a task will add it to an internal `ThreadPoolExecutor` queue. The task will be removed from the queue when one of the worker threads becomes available, i.e., after finishing its current task. If all workers are busy and all their current tasks are waiting for results from tasks that are waiting in the queue, the program will run indefinitely as no worker will be able to complete its task and take one of the blocking tasks from the queue. > [!NOTE] > Prerequisite to understand this page: @@ -162,11 +164,11 @@ browser_manager = BankingService(5) browser_manager.for_each_client() ``` -For the sake of the example, let's assume we have 5 clients, with 5 accounts and 5 cards for each account `number_of_times = 5`. In that case, we end up calling `check_card_validity() 125` times, exhausting `_max_workers` which is typically at around `32`. [Source: Python Docs] You can additionally call `self.executor._work_queue.qsize()` to get the exact number of tasks that are waiting in the queue, unable to be executed by the already busy workers. +For the sake of the example, let's assume we have 5 clients, with 5 accounts and 5 cards for each account `number_of_times = 5`. In that case, we end up calling `check_card_validity() 125` times, exhausting `_max_workers`. You can additionally call `self.executor._work_queue.qsize()` to get the exact number of tasks that are waiting in the queue, unable to be executed by the already busy workers. ## Compliant Solution (Caller runs when there are no available workers) -Python, as opposed to Java, does not provide `CallerRunsPolicy`, which was suggested as a solution in [Gafter, 2006]. It is possible to recreate that functionality by manually keeping a count of currently executed tasks. +Python, as opposed to Java, does not provide `CallerRunsPolicy`, which was suggested as a solution in [Gafter, 2006]. CallerRunsPolicy is a rejection policy used in Java's ThreadPoolExecutor to handle situations when the thread pool is saturated. It is possible to recreate that functionality by manually keeping a count of currently executed tasks. *[compliant02.py](compliant02.py):* diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/README.md index 6a374784..488aa95b 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/README.md @@ -1,5 +1,7 @@ # CWE-1335: Promote readability and compatibility by using mathematical written code with arithmetic operations instead of bit-wise operations +Avoid using bitwise operations for calculations, write math as math instead to ensure code clarity, compatibility and maintainability. + `C` and `C++` used to have two design patterns in order to optimize resource utilization: * Bit-wise operations for divisions or multiplication shifting the whole content of a variable to left or right for increased speed. @@ -12,6 +14,9 @@ The `example01.py` code demonstrates bit-wise operators available in Python. *[example01.py](example01.py):* ```py +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +"""example code""" foo = 50 bar = 42 print(f"foo = {foo} = {foo:08b}") # :08b is just for pretty print @@ -40,17 +45,20 @@ foo | bar = 00111010 foo ^ bar = 00011000 ``` -The `example02.py` code demonstrates how Python 2 changes an int to long to prevent an overflow condition while Python 3 is always storing an `int` as `long` [[Python 3.10.5 2022]](https://rushter.com/blog/python-integer-implementation/). +The `example02.py` code demonstrates how Python 2 changes an `int` to `long` to prevent an overflow condition while Python 3 is always storing an `int` as `long` [[Python 3.10.5 2022]](https://rushter.com/blog/python-integer-implementation/). *[example02.py](example02.py):* ```py +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT +"""example code""" for shift in [16, 32, 64]: bar = 5225 << shift print("foo << " + str(shift) + ": type " + str(type(bar)) + " " + str(bin(bar))) ``` -Left shift in `example02.py` changes type to long class in Python 2: +Left shift in `example02.py` changes type to `long` class in Python 2: ```bash foo << 16: type 0b10100011010010000000000000000 @@ -58,7 +66,7 @@ foo << 32: type 0b101000110100100000000000000000000000000000000 foo << 64: type 0b10100011010010000000000000000000000000000000000000000000000000000000000000000 ``` -Left shift in `example02.py` stays type int class but stores as long Python 3: +Left shift in `example02.py` stays type `int` class but stores as `long` Python 3: ```bash foo << 16: type 0b10100011010010000000000000000 @@ -73,12 +81,14 @@ Multiplication by `4` can be archived by a `2x` left. The `noncompliant01.py` co *[noncompliant01.py](noncompliant01.py):* ```py +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Non-compliant Code Example """ print(8 << 2 + 10) ``` -The `noncompliaint01.py` code results in printing `32768` instead of `42`. Adding brackets `print((8 << 2) + 10)` would fix this specific issue whilst still remaining prune to other issues. +The `noncompliant01.py` code results in printing `32768` instead of `42`. Adding brackets `print((8 << 2) + 10)` would fix this specific issue whilst still remaining prune to other issues. ## Compliant Solution (Left Shift) @@ -87,6 +97,8 @@ The statement in `compliant01.py` clarifies the programmer's intention. *[compliant01.py](compliant01.py):* ```py +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Compliant Code Example """ print(8 * 4 + 10) @@ -96,11 +108,13 @@ It is recommended by *[CWE-191, Integer Underflow (Wrap or Wraparound)](../../CW ## Non-compliant Code Example (Right Shift) -In this non-compliant code example is using an arithmetic right shift >>= operator in an attempt to optimize performance for dividing x by 4 without floating point. +The `noncompliant02.py` code example is using an arithmetic right shift `>>=` operator in an attempt to optimize performance for dividing `x` by `4` without floating point. *[noncompliant02.py](noncompliant02.py):* ```py +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Non-compliant Code Example """ foo: int @@ -118,6 +132,8 @@ The right shift is replaced by division in `compliant02.py`. *[compliant02.py](compliant02.py):* ```py +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Compliant Code Example """ foo: int = -50 diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example01.py b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example01.py index ae0cc73e..f0032bf8 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example01.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example01.py @@ -1,5 +1,6 @@ # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT +"""example code""" foo = 50 bar = 42 print(f"foo = {foo} = {foo:08b}") # :08b is just for pretty print diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example02.py b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example02.py index 8a02fd3d..91b9f891 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example02.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/01/example02.py @@ -1,5 +1,6 @@ # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT +"""example code""" for shift in [16, 32, 64]: bar = 5225 << shift print("foo << " + str(shift) + ": type " + str(type(bar)) + " " + str(bin(bar))) \ No newline at end of file diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/README.md index 5cf62a57..d35a4839 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-1335/README.md @@ -1,5 +1,7 @@ # CWE-1335: Incorrect Bitwise Shift of Integer +Avoid mixing bitwise shifts with arithmetic operations, instead, use clear mathematical expressions instead to maintain predictable behavior, readability, and compatibility. + Ensure to know what bit-wise shift operators do in case you can not avoid them as recommended in *NUM01-J. Do not perform bitwise and arithmetic operations on the same data* [[SEI CERT JAVA 2024]](https://wiki.sei.cmu.edu/confluence/display/java/NUM01-J.+Do+not+perform+bitwise+and+arithmetic+operations+on+the+same+data) and use math instead. A need to use bit-wise operations in Python can be due to translations or dealings with `C`, `C++` or `Java`, system libraries, raw binary data, or cryptographic algorithms. Existing Python modules hooking into system `C` libraries for cryptographic functions or math all to avoid the need to implement bit-shifting on a Python level. Bit-shifting can have unexpected outcomes. Python's ctypes module allows integration of `C` based system libraries into Python and direct access to C-type variables that can have different behavior than using high-level Python. diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/README.md index ed5e9bb1..9f6aa517 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/README.md @@ -10,13 +10,15 @@ Ensure that integer overflow is properly handled in order to avoid unexpected be Developers should follow the `C` guidelines when using or interacting with `C` type variables. -## Non-Compliant Code Example +## Non-Compliant Code Example -- Using numpy.int64 Using a `numpy.int64` can cause an unintentional flip of its sign when reaching the maximum number that can be stored as demonstrated in `noncompliant01.py`. *[noncompliant01.py](noncompliant01.py):* ```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Non-compliant Code Example """ import numpy @@ -35,13 +37,15 @@ An attempt to create `int` from a too big number causes an `OverflowError` and s > [!NOTE] > It has been observed that different results may occur depending on the version of `numpy`. For reference, we are using `numpy 1.23.1` and Python `3.9.12.` -## Compliant Solution +## Compliant Solution -- Using numpy.int64 The `compliant01.py` code detects the integer overflow by catching the appropriate Exception. *[compliant01.py](compliant01.py):* ```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Compliant Code Example """ import warnings @@ -52,17 +56,17 @@ a = numpy.int64(numpy.iinfo(numpy.int64).max) with warnings.catch_warnings(): try: print(a + 1) - except Warning as _: + except Warning: print("Failed to increment " + str(a) + " due to overflow error") # RuntimeWarning and continues try: b = numpy.int64(numpy.iinfo(numpy.int64).max + 1) # OverflowError and stops -except OverflowError as e: +except OverflowError: print("Failed to assign value to B due to overflow error") ``` -## Non-Compliant Code Example +## Non-Compliant Code Example -- Using datetime.timedelta() The `noncompliant02.py` example uses `datetime.timedelta()` to get `x` hours in the future or past for time travelers. The `datetime` is interfacing with the operating system through the `libpython` library written in `C`. Overall the Georgian calender ISO 8601 is limited to 1 - 9999 years [Python datetime 2025](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes). @@ -125,7 +129,7 @@ The `noncompliant02.py` code is triggering various `OverflowError` exceptions in - `OverflowError('Python int too large to convert to C int')` - `days=1000000000; must have magnitude <= 999999999` -## Compliant Solution +## Compliant Solution -- Using datetime.timedelta() This `compliant02.py` solution is preventing `OverflowError` exception in `libpython` by safeguarding the upper and lower limits in the provided `hours`. Upper and lower limit for `currtime` as well as input sanitization and secure logging are missing and must be added when interfacing with a lesser trusted entity. @@ -207,13 +211,15 @@ for hours in hours_list: The `compliant02.py` example is protecting the lower level c-lib from an `OverflowError` by setting boundaries for valid values in `hours`. Similar issues occur with any functionality provided through the operating system. -## Non-Compliant Code Example +## Non-Compliant Code Example -- Using math.exp The `noncompliant03.py` code example results in a `OverflowError: math range error`. This is due to `math.exp` being a `C` implementation behind the scenes for better performance. So while it returns a `Python float` it does use `C` type of variables internally for the calculation in `mathmodule.c` [[cpython 2024]](https://github.com/python/cpython/blob/main/Modules/mathmodule.c). *[noncompliant03.py](noncompliant03.py):* ```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Non-compliant Code Example """ import math @@ -231,13 +237,15 @@ print(calculate_exponential_value(1000)) ``` -## Compliant Solution +## Compliant Solution -- Using math.exp This `compliant03.py` solution detects the `integer` overflow by catching the appropriate Exception on overflow: *[compliant03.py](compliant03.py):* ```python +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Compliant Code Example """ import math @@ -246,7 +254,7 @@ def calculate_exponential_value(number): """Return 'E' raised to the power of different numbers:""" try: return math.exp(number) - except OverflowError as _: + except OverflowError: return "Number " + str(number) + " caused an integer overflow" diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant01.py b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant01.py index 071061f4..d917f5c3 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant01.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant01.py @@ -10,11 +10,11 @@ with warnings.catch_warnings(): try: print(a + 1) - except Warning as _: + except Warning: print("Failed to increment " + str(a) + " due to overflow error") # RuntimeWarning and continues try: b = numpy.int64(numpy.iinfo(numpy.int64).max + 1) # OverflowError and stops -except OverflowError as e: +except OverflowError: print("Failed to assign value to B due to overflow error") diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant03.py b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant03.py index 0816f568..6de41f90 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant03.py +++ b/docs/Secure-Coding-Guide-for-Python/CWE-682/CWE-191/compliant03.py @@ -1,3 +1,5 @@ +# SPDX-FileCopyrightText: OpenSSF project contributors +# SPDX-License-Identifier: MIT """ Compliant Code Example """ import math @@ -6,7 +8,7 @@ def calculate_exponential_value(number): """Return 'E' raised to the power of different numbers:""" try: return math.exp(number) - except OverflowError as _: + except OverflowError: return "Number " + str(number) + " caused an integer overflow" diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-691/CWE-617/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-691/CWE-617/README.md index 3671a2d9..0b1cbbca 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-691/CWE-617/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-691/CWE-617/README.md @@ -2,11 +2,11 @@ Assertions are a useful developer tool, but they cannot be relied upon to be present in a production environment. Incorrect function arguments should be handled by an appropriate exception. -Python removes assertions when a script is run with the `-O` and `-OO` options [[Python 3.9 Documentation](https://docs.python.org/3.9/using/cmdline.html?highlight=pythonoptimize#cmdoption-o)]. +Python removes assertions when a script is run with the `-O` and `-OO` options [[Python 3.9 Documentation](https://docs.python.org/3.9/using/cmdline.html?highlight=pythonoptimize#cmdoption-o)]. The `-O` options is for optimisation. It removes asserts statements from bytecode, removes docstrings from functions/classes and sets `__debug__` to False. It is used for slightly faster execution and smaller bytecode files. `-OO` does everything that `-O`does but it additionally removes module-level docstrings and creates an even more compact bytecode. ## Non-Compliant Code Example -The code is checking for invalid arguments by using assertions. In this example, any positive integer between `1-709` inclusive is valid, and any other argument is invalid. +The non-compliant code example is checking for invalid arguments by using assertions. In this example, any positive integer between `1-709` inclusive is valid, and any other argument is invalid. If the script is run normally, the assertions will catch the invalid arguments. If the script is run in optimized mode, assertions are removed from the bytecode and the function will not work as intended. To simplify the exploit code, the specific exception raised by the argument is caught. @@ -53,21 +53,23 @@ try: except (AssertionError, OverflowError, TypeError, ValueError) as e: print(e) -# output - -# $ python3.9 noncompliant01.py -# 2.718281828459045 -# 8.218407461554972e+307 -# Argument 710 is not valid -# Argument 0 is not valid -# Argument b is not valid -# $ python3.9 -O noncompliant01.py -# 2.718281828459045 -# 8.218407461554972e+307 -# math range error -# 1.0 -# must be real number, not str +``` + __Output of noncompliant01.py:__ + +```bash +$ python3.9 noncompliant01.py +2.718281828459045 +8.218407461554972e+307 +Argument 710 is not valid +Argument 0 is not valid +Argument b is not valid +$ python3.9 -O noncompliant01.py +2.718281828459045 +8.218407461554972e+307 +math range error +1.0 +must be real number, not str ``` ## Compliant Solution @@ -115,22 +117,24 @@ try: print(my_exp("b")) except (AssertionError, OverflowError, TypeError, ValueError) as e: print(e) - -# output - -# $ python3.9 compliant01.py -# 2.718281828459045 -# 8.218407461554972e+307 -# Argument 710 is not valid -# Argument 0 is not valid -# Argument b is not valid -# $ python3.9 -O compliant01.py -# 2.718281828459045 -# 8.218407461554972e+307 -# Argument 710 is not valid -# Argument 0 is not valid -# Argument b is not valid +``` + + __Output of compliant01.py:__ + +```bash +$ python3.9 compliant01.py +2.718281828459045 +8.218407461554972e+307 +Argument 710 is not valid +Argument 0 is not valid +Argument b is not valid +$ python3.9 -O compliant01.py +2.718281828459045 +8.218407461554972e+307 +Argument 710 is not valid +Argument 0 is not valid +Argument b is not valid ``` ## Automated Detection diff --git a/docs/Secure-Coding-Guide-for-Python/CWE-693/CWE-184/README.md b/docs/Secure-Coding-Guide-for-Python/CWE-693/CWE-184/README.md index 4d11e1a2..33aa7879 100644 --- a/docs/Secure-Coding-Guide-for-Python/CWE-693/CWE-184/README.md +++ b/docs/Secure-Coding-Guide-for-Python/CWE-693/CWE-184/README.md @@ -6,14 +6,14 @@ Avoid Incomplete 'deny lists' that can lead to security vulnerabilities such as The `noncompliant01.py` code demonstrates the difficult handling of exclusion lists in a multi language support use case. `UTF-8` has __1,112,064__ mappings between `8-32` bit values and printable characters such as `生` known as "code points". -The `noncompliant01.py` `filterString()` method attempts to search for disallowed inputs and fails to find the `script` tag due to the non-English character `生` in ``. +The `noncompliant01.py` `filterString()` method attempts to search for disallowed inputs and fails to find the `script` tag due to the non-English character `生` in ``. Failure to filter such strings could lead to Cross-Site Scripting (XSS) injection, as per [CWE-182: Collapse of Data into Unsafe Value](../CWE-182/README.md) *[noncompliant01.py](noncompliant01.py):* ```python # SPDX-FileCopyrightText: OpenSSF project contributors # SPDX-License-Identifier: MIT -"""Compliant Code Example""" +""" Non-compliant Code Example """ import re import sys @@ -34,6 +34,10 @@ def filter_string(input_string: str): for tag in re.findall("<[^>]*>", input_string): if tag in ["