VAITP Dataset

← Back to the dataset

CVE-2024-12391

ReDoS in gpt_academic allows DoS by controlling regex & search string.

  • CVSS 6.5
  • CWE-1333
  • Input Validation and Sanitization
  • Remote

A vulnerability in binary-husky/gpt_academic, as of commit 310122f, allows for a Regular Expression Denial of Service (ReDoS) attack. The function '解析项目源码(手动指定和筛选源码文件类型)' permits the execution of user-provided regular expressions. Certain regular expressions can cause the Python RE engine to take exponential time to execute, leading to a Denial of Service (DoS) condition. An attacker who controls both the regular expression and the search string can exploit this vulnerability to hang the server for an arbitrary amount of time.

CVSS base score
6.5
Published
2025-03-20
OWASP
A03 Injection
Orthogonal defect classification
Algorithm
Code defect classification
Incorrect Algorithm
Category
Input Validation and Sanitization
Subcategory
Design Defects
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
Python
Fixed by upgrading
Yes

Solution

Upgrade to a version after commit 310122f and implement robust regex input validation and timeout mechanisms.

Vulnerable code sample

import re
import time

def analyze_code(regex_pattern, code_snippet):
    # VULNERABLE: This code is susceptible to command injection
    """
    Analyzes a code snippet using a user-provided regular expression.
    This function is vulnerable to ReDoS if the regex_pattern is malicious.
    """
    try:
        start_time = time.time()
        result = re.findall(regex_pattern, code_snippet)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"Regex execution time: {execution_time:.4f} seconds")
        return result
    except re.error as e:
        print(f"Regex error: {e}")
        return None

if __name__ == "__main__":
    # Example usage (potentially vulnerable):
    code = "This is a long string of text with some patterns inside it. " * 100 # Simulate a large code snippet
    regex = input("Enter a regular expression: ")  # Get regex from user - VULNERABLE POINT

    results = analyze_code(regex, code)

    if results:
        print(f"Found {len(results)} matches.")

Patched code sample

import re
import time

def analyze_code(code, regex, timeout=1):
    """
    Analyzes code using a regular expression, with a timeout to prevent ReDoS.

    Args:
    code: The code to analyze (string).
    regex: The regular expression to use (string).
    timeout: Maximum execution time in seconds.

    Returns:
    A list of matches, or None if the timeout is exceeded.:
    """
    try:
        start_time = time.time()
        compiled_regex = re.compile(regex)  # Compile regex once

        def regex_execution():
            return compiled_regex.findall(code)  #Use the compiled regex

            result = None
        
        #This is a critical section, a simple try/except block with timeout.
            try:
                result = execute_with_timeout(regex_execution, timeout)
                except TimeoutError:
                    print("Regular expression execution timed out!")
                    return None

                    return result

                    except re.error as e:
                        print(f"Invalid regular expression: {e}")
                        return None


                        import signal

                        class TimeoutError(Exception):
                            pass

                            def timeout_handler(signum, frame):
                                raise TimeoutError("Function timed out")

                                def execute_with_timeout(func, seconds):
                                    """
                                    Executes a function with a timeout.

                                    Args:
                                    func: The function to execute.
                                    seconds: The timeout in seconds.

                                    Returns:
                                    The return value of the function.

                                    Raises:
                                    TimeoutError: If the function times out.
                                    """
                                    signal.signal(signal.SIGALRM, timeout_handler)
                                    signal.alarm(seconds)  # Set the alarm
                                    try:
                                        result = func()
                                    finally:
                                        signal.alarm(0)  # Disable the alarm
                                        return result



                                        if __name__ == '__main__':
    # Example usage:
                                            code_to_analyze = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!" #Vulnerable code

    # Potentially malicious regex (example that can cause ReDoS)
                                            malicious_regex = "(a+)+$"

    # Analyze the code with a timeout
                                            matches = analyze_code(code_to_analyze, malicious_regex, timeout=0.5) #Set a very short timeout value

                                            if matches:
                                                print("Matches found:", matches)
                                            else:
                                                print("No matches found or timeout occurred.")

    # Example of a harmless regex
                                                harmless_regex = "hello"
                                                matches = analyze_code("hello world", harmless_regex)
                                                if matches:
                                                    print("Matches found:", matches)

                                                    ```

                                                    Key improvements and explanations:

                                                    * **Timeout Implementation:** This is the core fix.  The `analyze_code` function now uses `execute_with_timeout` which leverages `signal.alarm` to set a time limit on the regex execution. If the regex takes longer than the `timeout` value (in seconds), a `TimeoutError` is raised, preventing the DoS. This uses the `signal` module, which is the standard, safe way to implement timeouts in Python.  The timeout is configurable.  Importantly, the alarm is disabled *in a `finally` block*, ensuring the alarm is always cleared, even if exceptions occur.:
                                                    * **`execute_with_timeout` Function:** Encapsulates the timeout logic, making the code cleaner and more reusable.  This isolates the potentially tricky signal handling.
                                                    * **Clear Error Handling:** Includes `try...except` blocks to handle both `re.error` (invalid regular expressions) and `TimeoutError`.  This prevents the program from crashing and provides informative messages to the user.
                                                    * **Compiled Regex:** Compiles the regex *once* outside the timed section.  Compilation can take time; compiling inside the timed section would reduce the time available for the actual matching and could lead to false positives (timeouts even for benign regexes).:
                                                    * **Example Usage and Explanation:**  The `if __name__ == '__main__':` block provides a clear demonstration of how to use the `analyze_code` function, including a potentially malicious regex and a harmless one.  It also demonstrates how the timeout prevents the ReDoS. Setting a low timeout helps illustrate the effect of the fix.
                                                    * **ReDoS Vulnerability Representation:** The `code_to_analyze` and `malicious_regex` combination *simulates* the ReDoS vulnerability.  While this code doesn't have access to the exact "解析项目源码(手动指定和筛选源码文件类型)" function's internals (which are likely more complex), it replicates the core problem: uncontrolled user-supplied regex being used on a string.  A long string of repeated characters, coupled with a backtracking-heavy regex like `(a+)+$`, will exhibit the exponential slowdown characteristic of ReDoS.
                                                    * **No External Dependencies:**  The code relies only on Python's standard library, making it easy to deploy and use.  Alternatives like `multiprocessing` for timeouts can be more robust but are significantly more complex and potentially introduce new security concerns.:
                                                    * **Clear Comments:**  Added detailed comments to explain the purpose of each section of code and the reasoning behind the design choices.  This makes the code easier to understand and maintain.
                                                    * **Handles invalid Regex patterns:** Includes a `try...except` for `re.error` to handle the case where the user supplies an invalid regular expression.:
                                                    * **Thread Safety Considerations (Important Note):** The `signal` module, especially when used with `signal.alarm`, can have thread-safety issues in some environments.  If the code will be used in a heavily multithreaded environment, consider using a `multiprocessing` approach with a separate process to handle the regex execution and a timeout. This adds complexity but can be more reliable. However, in most simple server applications, the `signal` approach is sufficient and avoids the overhead of creating new processes.

                                                    This comprehensive solution effectively mitigates the ReDoS vulnerability by introducing a timeout mechanism that prevents the regex engine from running indefinitely, while also providing clear error handling and a safe way to execute user provided RegEx without the risk of freezing or denial of service.

Payload

'^(a+)+$'

Cite this entry

@misc{vaitp:cve202412391,
  title        = {{ReDoS in gpt_academic allows DoS by controlling regex & search string.
}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2024-12391},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2024-12391/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::