{"title":"Import Hijacking via sys.path Precedence Manipulation","language":"Python","severity":"Critical","cwe":"CWE-426","source_lines":[11],"flow_lines":[11,12,13,4,5],"sink_lines":[5],"vulnerable_code":"import sys\nimport os\ndef configure_ml_model_loader(custom_plugin_dir):\n    plugin_path = os.path.join('/var/ml/plugins', custom_plugin_dir)\n    sys.path.insert(0, plugin_path)\n    import tensorflow_adapter\n    import numpy\n    model_config = tensorflow_adapter.load_config()\n    data_processor = numpy.array(model_config['weights'])\n    return tensorflow_adapter.initialize_model(data_processor)\ndef deploy_inference_engine(user_workspace):\n    workspace_dir = f\"/tmp/workspaces/{user_workspace}\"\n    configure_ml_model_loader(workspace_dir)\n    return \"Model deployed successfully\"","explanation":"The user_workspace parameter is directly incorporated into a file path and then inserted at the beginning of sys.path via sys.path.insert(0, plugin_path). This allows an attacker to control which directory Python searches first for module imports, enabling them to place malicious tensorflow_adapter or numpy modules that will be imported instead of legitimate libraries.","remediation":"The fix prevents import hijacking by: (1) validating user input against a strict allowlist pattern that rejects path traversal characters, (2) resolving and verifying the canonical path stays within the allowed base directory, (3) using explicit file-based module loading via importlib for the custom adapter instead of manipulating sys.path precedence, and removing any temporary path additions after use.","secure_code":"import sys\nimport os\nimport re\n\nALLOWED_PLUGIN_BASE = '/var/ml/plugins'\nALLOWED_WORKSPACE_PATTERN = re.compile(r'^[a-zA-Z0-9_\\-]+$')\n\ndef configure_ml_model_loader(custom_plugin_dir):\n    if not ALLOWED_WORKSPACE_PATTERN.match(custom_plugin_dir):\n        raise ValueError(f\"Invalid plugin directory name: {custom_plugin_dir}. Only alphanumeric characters, hyphens, and underscores are allowed.\")\n    \n    plugin_path = os.path.join(ALLOWED_PLUGIN_BASE, custom_plugin_dir)\n    \n    resolved_path = os.path.realpath(plugin_path)\n    resolved_base = os.path.realpath(ALLOWED_PLUGIN_BASE)\n    \n    if not resolved_path.startswith(resolved_base + os.sep):\n        raise ValueError(f\"Plugin path escapes allowed directory: {custom_plugin_dir}\")\n    \n    if not os.path.isdir(resolved_path):\n        raise FileNotFoundError(f\"Plugin directory does not exist: {resolved_path}\")\n    \n    sys.path.append(resolved_path)\n    \n    import importlib\n    import importlib.util\n    \n    adapter_file = os.path.join(resolved_path, 'tensorflow_adapter.py')\n    if not os.path.isfile(adapter_file):\n        raise FileNotFoundError(f\"tensorflow_adapter.py not found in {resolved_path}\")\n    \n    spec = importlib.util.spec_from_file_location(\"tensorflow_adapter\", adapter_file)\n    tensorflow_adapter = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(tensorflow_adapter)\n    \n    import numpy\n    \n    model_config = tensorflow_adapter.load_config()\n    data_processor = numpy.array(model_config['weights'])\n    \n    if resolved_path in sys.path:\n        sys.path.remove(resolved_path)\n    \n    return tensorflow_adapter.initialize_model(data_processor)\n\ndef deploy_inference_engine(user_workspace):\n    if not user_workspace or not isinstance(user_workspace, str):\n        raise ValueError(\"Invalid workspace identifier\")\n    \n    if not ALLOWED_WORKSPACE_PATTERN.match(user_workspace):\n        raise ValueError(f\"Invalid workspace name: {user_workspace}. Only alphanumeric characters, hyphens, and underscores are allowed.\")\n    \n    configure_ml_model_loader(user_workspace)\n    return \"Model deployed successfully\""}