{"title":"Import Hijacking via Unsafe sys.path Precedence","language":"Python","severity":"Critical","cwe":"CWE-427","source_lines":[3],"flow_lines":[3,4,7],"sink_lines":[7],"vulnerable_code":"import sys\nimport os\ndef load_cloud_credentials(tenant_id):\n    config_dir = os.path.join('/tmp/azure_configs', tenant_id)\n    if not os.path.exists(config_dir):\n        os.makedirs(config_dir)\n    sys.path.insert(0, config_dir)\n    import azure_auth\n    creds = azure_auth.get_service_principal()\n    return creds\ndef authenticate_to_azure(tenant):\n    credentials = load_cloud_credentials(tenant)\n    return credentials['client_secret']","explanation":"The tenant_id parameter is user-controlled and used to construct a directory path that is inserted at the highest precedence in sys.path. An attacker can supply a malicious tenant_id pointing to a directory containing a crafted azure_auth.py module, which will be imported instead of the legitimate module, enabling arbitrary code execution.","remediation":"The fix validates tenant_id against a strict allowlist pattern to prevent path traversal, uses a secure base directory instead of /tmp, resolves the path and verifies it remains within the base directory, and uses importlib.util.spec_from_file_location to load the module directly from an explicit file path without modifying sys.path precedence.","secure_code":"import sys\nimport os\nimport importlib.util\nimport re\n\nALLOWED_TENANT_PATTERN = re.compile(r'^[a-zA-Z0-9_-]+$')\nBASE_CONFIG_DIR = '/opt/azure_configs'\n\ndef load_cloud_credentials(tenant_id):\n    # Validate tenant_id to prevent path traversal\n    if not tenant_id or not ALLOWED_TENANT_PATTERN.match(tenant_id):\n        raise ValueError(f\"Invalid tenant_id: must be alphanumeric, hyphens, or underscores only\")\n    \n    config_dir = os.path.join(BASE_CONFIG_DIR, tenant_id)\n    # Resolve to absolute path and verify it stays within the base directory\n    config_dir = os.path.realpath(config_dir)\n    if not config_dir.startswith(os.path.realpath(BASE_CONFIG_DIR) + os.sep):\n        raise ValueError(f\"Invalid tenant_id: path traversal detected\")\n    \n    module_path = os.path.join(config_dir, 'azure_auth.py')\n    if not os.path.isfile(module_path):\n        raise FileNotFoundError(f\"Authentication module not found for tenant: {tenant_id}\")\n    \n    # Load module from explicit file path without modifying sys.path\n    spec = importlib.util.spec_from_file_location(\"azure_auth\", module_path)\n    if spec is None or spec.loader is None:\n        raise ImportError(f\"Cannot load authentication module for tenant: {tenant_id}\")\n    \n    azure_auth = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(azure_auth)\n    \n    creds = azure_auth.get_service_principal()\n    return creds\n\ndef authenticate_to_azure(tenant):\n    credentials = load_cloud_credentials(tenant)\n    return credentials['client_secret']"}