{"title":"Import Hijacking via sys.path Precedence","language":"Python","severity":"Critical","cwe":"CWE-426","source_lines":[3],"flow_lines":[3,5,7],"sink_lines":[7],"vulnerable_code":"import sys\nimport os\ndef load_cloud_credentials(tenant_id):\n    user_plugin_dir = f\"/var/app/tenants/{tenant_id}/plugins\"\n    if os.path.exists(user_plugin_dir):\n        sys.path.insert(0, user_plugin_dir)\n    import azure_auth\n    creds = azure_auth.get_service_principal()\n    return creds\ndef authenticate_azure_resource(tenant_id, resource_name):\n    credentials = load_cloud_credentials(tenant_id)\n    return credentials.connect(resource_name)","explanation":"The tenant_id parameter flows from untrusted input into a path construction that is added to sys.path, allowing an attacker to inject a malicious module path. When the import statement executes, Python searches sys.path in order and loads the attacker's malicious azure_auth module instead of the legitimate one, enabling credential theft or code execution.","remediation":"The fix eliminates the sys.path manipulation entirely and instead loads the azure_auth module exclusively from a trusted, hardcoded file path using importlib.util.spec_from_file_location. Additionally, the tenant_id is strictly validated against an allowlist regex pattern to prevent path traversal attacks, ensuring no attacker-controlled input can influence module loading.","secure_code":"import sys\nimport os\nimport importlib\nimport importlib.util\nimport re\n\nALLOWED_TENANT_ID_PATTERN = re.compile(r'^[a-zA-Z0-9_-]+$')\nTRUSTED_AZURE_AUTH_PATH = \"/opt/app/lib/azure_auth.py\"\n\ndef _load_trusted_azure_auth():\n    \"\"\"Load azure_auth exclusively from the trusted, known location.\"\"\"\n    spec = importlib.util.spec_from_file_location(\"azure_auth\", TRUSTED_AZURE_AUTH_PATH)\n    if spec is None or spec.loader is None:\n        raise ImportError(f\"Cannot load trusted azure_auth module from {TRUSTED_AZURE_AUTH_PATH}\")\n    module = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(module)\n    return module\n\ndef _validate_tenant_id(tenant_id):\n    \"\"\"Validate tenant_id to prevent path traversal attacks.\"\"\"\n    if not tenant_id or not isinstance(tenant_id, str):\n        raise ValueError(\"Invalid tenant_id: must be a non-empty string\")\n    if not ALLOWED_TENANT_ID_PATTERN.match(tenant_id):\n        raise ValueError(f\"Invalid tenant_id: contains disallowed characters: {tenant_id}\")\n    return tenant_id\n\ndef load_cloud_credentials(tenant_id):\n    \"\"\"Load cloud credentials using only the trusted azure_auth module.\n    \n    Tenant-specific plugin directories are NOT added to sys.path to prevent\n    import hijacking attacks.\n    \"\"\"\n    validated_tenant_id = _validate_tenant_id(tenant_id)\n    \n    # Load azure_auth from a trusted, fixed path only\n    azure_auth = _load_trusted_azure_auth()\n    creds = azure_auth.get_service_principal(validated_tenant_id)\n    return creds\n\ndef authenticate_azure_resource(tenant_id, resource_name):\n    credentials = load_cloud_credentials(tenant_id)\n    return credentials.connect(resource_name)"}