{"title":"Import Hijacking via Untrusted sys.path Precedence","language":"Python","severity":"Critical","cwe":"CWE-426","source_lines":[3],"flow_lines":[3,4,5,6],"sink_lines":[6],"vulnerable_code":"import sys\nimport os\ndef load_cloud_credentials(tenant_id, config_dir):\n    user_config_path = os.path.join('/var/app/tenants', tenant_id, config_dir)\n    if os.path.exists(user_config_path):\n        sys.path.insert(0, user_config_path)\n    import azure_auth\n    vault_client = azure_auth.get_key_vault_client()\n    secrets = vault_client.retrieve_all_secrets()\n    return secrets\ndef provision_tenant_resources(tenant_id):\n    creds = load_cloud_credentials(tenant_id, 'config')\n    return creds","explanation":"The tenant_id parameter (untrusted input) is used to construct a file path that gets prepended to sys.path via sys.path.insert(0, user_config_path). A malicious tenant can place a fake azure_auth.py module in their config directory, which will be imported instead of the legitimate module, allowing credential interception and privilege escalation across tenant boundaries.","remediation":"The fix eliminates sys.path manipulation entirely by loading the azure_auth module exclusively from a trusted, hardcoded file path using importlib.util.spec_from_file_location. Tenant-specific configuration is loaded only as data (JSON) from validated, path-traversal-protected directories, ensuring no tenant-controlled code can be executed.","secure_code":"import sys\nimport os\nimport importlib\nimport importlib.util\n\nAZURE_AUTH_MODULE_PATH = '/opt/app/lib/azure_auth.py'\n\ndef load_azure_auth_module():\n    \"\"\"Load azure_auth module from a trusted, fixed location only.\"\"\"\n    if not os.path.isfile(AZURE_AUTH_MODULE_PATH):\n        raise ImportError(f\"Trusted azure_auth module not found at {AZURE_AUTH_MODULE_PATH}\")\n    spec = importlib.util.spec_from_file_location(\"azure_auth\", AZURE_AUTH_MODULE_PATH)\n    if spec is None or spec.loader is None:\n        raise ImportError(f\"Cannot load module spec from {AZURE_AUTH_MODULE_PATH}\")\n    module = importlib.util.module_from_spec(spec)\n    spec.loader.exec_module(module)\n    return module\n\ndef load_tenant_config(tenant_id, config_dir):\n    \"\"\"Load tenant-specific configuration data (non-executable) safely.\"\"\"\n    safe_tenant_id = os.path.basename(tenant_id)\n    safe_config_dir = os.path.basename(config_dir)\n    tenant_config_path = os.path.join('/var/app/tenants', safe_tenant_id, safe_config_dir)\n    real_path = os.path.realpath(tenant_config_path)\n    allowed_base = os.path.realpath('/var/app/tenants')\n    if not real_path.startswith(allowed_base + os.sep):\n        raise ValueError(f\"Invalid tenant config path: path traversal detected\")\n    config = {}\n    config_file = os.path.join(real_path, 'tenant_settings.json')\n    if os.path.isfile(config_file):\n        import json\n        with open(config_file, 'r') as f:\n            config = json.load(f)\n    return config\n\ndef load_cloud_credentials(tenant_id, config_dir):\n    \"\"\"Load Azure Key Vault credentials using trusted module only.\"\"\"\n    tenant_config = load_tenant_config(tenant_id, config_dir)\n    azure_auth = load_azure_auth_module()\n    vault_client = azure_auth.get_key_vault_client(tenant_config=tenant_config)\n    secrets = vault_client.retrieve_all_secrets()\n    return secrets\n\ndef provision_tenant_resources(tenant_id):\n    creds = load_cloud_credentials(tenant_id, 'config')\n    return creds"}