# Regex DoS via Catastrophic Backtracking

Language: Python
Severity: High
CWE: CWE-1333

## Source
12

## Flow
12-13-4-5

## Sink
5

## Vulnerable Code
```python
import re
from flask import request, jsonify

def validate_iot_device_firmware_version(firmware_string):
    version_pattern = r'^(v?\d+\.)*\d+(-[a-zA-Z0-9]+)*$'
    if re.match(version_pattern, firmware_string):
        return jsonify({"status": "valid", "version": firmware_string})
    return jsonify({"status": "invalid"}), 400

@app.route('/api/iot/firmware/validate', methods=['POST'])
def check_firmware_compatibility():
    device_firmware = request.json.get('firmware_version', '')
    return validate_iot_device_firmware_version(device_firmware)
```

## Explanation

The regex pattern r'^(v?\d+\.)*\d+(-[a-zA-Z0-9]+)*$' contains nested quantifiers that cause catastrophic backtracking. When malicious input with many repeating groups is provided, the regex engine exponentially backtracks trying all possible match combinations, causing CPU exhaustion and denial of service.

## Remediation

The fix applies two key mitigations: First, it enforces a strict maximum input length (128 characters) which prevents the regex engine from having enough input to cause meaningful CPU exhaustion through backtracking. Second, the regex groups use non-capturing syntax (?:...) which, combined with the input length restriction, makes catastrophic backtracking infeasible even on adversarial inputs. The length limit is the primary defense since firmware version strings should never be longer than a reasonable bound.

## Secure Code
```python
import re
from flask import request, jsonify

MAX_FIRMWARE_LENGTH = 128

def validate_iot_device_firmware_version(firmware_string):
    if not firmware_string or len(firmware_string) > MAX_FIRMWARE_LENGTH:
        return jsonify({"status": "invalid", "error": "Invalid firmware string length"}), 400

    version_pattern = r'^v?(?:\d+\.)*\d+(?:-[a-zA-Z0-9]+)*$'

    if re.match(version_pattern, firmware_string):
        return jsonify({"status": "valid", "version": firmware_string})
    return jsonify({"status": "invalid"}), 400

@app.route('/api/iot/firmware/validate', methods=['POST'])
def check_firmware_compatibility():
    device_firmware = request.json.get('firmware_version', '')
    return validate_iot_device_firmware_version(device_firmware)
```
