{"title":"Regex DoS via Catastrophic Backtracking in re.search()","language":"Python","severity":"High","cwe":"CWE-1333","source_lines":[8],"flow_lines":[8,10],"sink_lines":[10],"vulnerable_code":"import re\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/api/iot/validate_device_id', methods=['POST'])\ndef validate_iot_device_identifier():\n    device_id = request.json.get('device_identifier', '')\n    pattern = r'^(([a-zA-Z0-9]+)+)+@iot\\.device$'\n    if re.search(pattern, device_id):\n        return jsonify({'status': 'valid', 'device_id': device_id})\n    return jsonify({'status': 'invalid'}), 400","explanation":"The regex pattern `^(([a-zA-Z0-9]+)+)+@iot\\.device$` contains nested quantifiers that cause catastrophic backtracking when matching fails. Untrusted input from `request.json.get('device_identifier')` is directly passed to `re.search()` without input validation or timeout, allowing an attacker to craft malicious device IDs that exponentially increase regex evaluation time, leading to denial of service.","remediation":"The fix removes the nested quantifiers `(([a-zA-Z0-9]+)+)+` that caused catastrophic backtracking and replaces them with a simple `[a-zA-Z0-9]+` which matches one or more alphanumeric characters without any ambiguity. Additionally, input length validation is enforced before regex evaluation, and the pattern is pre-compiled using `re.compile()` with `match()` instead of `search()` for better performance and correctness with the `^` anchor.","secure_code":"import re\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n# Pre-compiled safe regex without nested quantifiers\nDEVICE_ID_PATTERN = re.compile(r'^[a-zA-Z0-9]+@iot\\.device$')\n\nMAX_DEVICE_ID_LENGTH = 256\n\n@app.route('/api/iot/validate_device_id', methods=['POST'])\ndef validate_iot_device_identifier():\n    device_id = request.json.get('device_identifier', '')\n    \n    # Input length validation to prevent abuse\n    if not device_id or len(device_id) > MAX_DEVICE_ID_LENGTH:\n        return jsonify({'status': 'invalid'}), 400\n    \n    if DEVICE_ID_PATTERN.match(device_id):\n        return jsonify({'status': 'valid', 'device_id': device_id})\n    return jsonify({'status': 'invalid'}), 400"}