{"title":"Regex DoS via Catastrophic Backtracking in re.match()","language":"Python","severity":"High","cwe":"CWE-1333","source_lines":[8],"flow_lines":[8,9,10],"sink_lines":[10],"vulnerable_code":"import re\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/api/iot/device/validate', methods=['POST'])\ndef validate_device_serial():\n    serial_number = request.json.get('device_serial', '')\n    pattern = r'^(([A-Z0-9]+)*-)*([A-Z0-9]+)+$'\n    if re.match(pattern, serial_number):\n        return jsonify({'status': 'valid', 'serial': serial_number})\n    return jsonify({'status': 'invalid'}), 400","explanation":"The code uses a regex pattern with nested quantifiers (([A-Z0-9]+)*-)*([A-Z0-9]+)+ that causes catastrophic backtracking when matching fails. An attacker can submit a specially crafted device serial number that forces the regex engine into exponential time complexity, leading to CPU exhaustion and denial of service.","remediation":"The fix replaces the vulnerable regex pattern that had nested quantifiers `(([A-Z0-9]+)*-)*([A-Z0-9]+)+` with a safe linear-time pattern `^[A-Z0-9]+(-[A-Z0-9]+)*$` that matches the same valid serial number format (alphanumeric segments separated by hyphens) without any ambiguous quantifier nesting. Additionally, an input length check of 128 characters is added as a defense-in-depth measure to prevent excessively long inputs from being processed.","secure_code":"import re\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/api/iot/device/validate', methods=['POST'])\ndef validate_device_serial():\n    serial_number = request.json.get('device_serial', '')\n    \n    # Input length limit to prevent abuse\n    if not serial_number or len(serial_number) > 128:\n        return jsonify({'status': 'invalid'}), 400\n    \n    # Safe regex without nested quantifiers - matches segments of alphanumeric chars separated by hyphens\n    pattern = r'^[A-Z0-9]+(-[A-Z0-9]+)*$'\n    if re.match(pattern, serial_number):\n        return jsonify({'status': 'valid', 'serial': serial_number})\n    return jsonify({'status': 'invalid'}), 400"}