{"title":"Import Hijacking via `sys.path` Precedence Abuse","language":"Python","severity":"Critical","cwe":"CWE-427","source_lines":[3],"flow_lines":[3,4,5,6],"sink_lines":[6],"vulnerable_code":"import sys\nimport os\ndef load_cloud_credentials(bucket_name):\n    plugin_dir = os.path.join('/var/app/plugins', bucket_name)\n    if os.path.exists(plugin_dir):\n        sys.path.insert(0, plugin_dir)\n    import boto3\n    from aws_config import get_session_token\n    token = get_session_token()\n    s3_client = boto3.client('s3', aws_access_key_id=token['key'], aws_secret_access_key=token['secret'])\n    return s3_client","explanation":"The function accepts user-controlled 'bucket_name' input and uses it to construct a directory path that is then inserted at the beginning of sys.path. This allows an attacker to control Python's module search order, enabling import hijacking where malicious modules (boto3.py or aws_config.py) placed in the attacker-controlled directory will be imported instead of legitimate ones, leading to credential theft.","remediation":"The fix moves all sensitive imports (boto3, aws_config) to the top of the module where they are resolved from the original sys.path before any user input is processed, completely eliminating the import hijacking vector. The user-controlled plugin directory is no longer added to sys.path; instead, plugin configuration is loaded as data files (JSON) rather than executable Python modules. Additionally, bucket_name is validated against S3 naming rules and the resolved path is checked to prevent directory traversal.","secure_code":"import sys\nimport os\nimport re\nimport importlib\nimport boto3\nfrom aws_config import get_session_token\n\ndef load_cloud_credentials(bucket_name):\n    # Validate bucket_name to prevent path traversal\n    if not re.match(r'^[a-zA-Z0-9][a-zA-Z0-9.\\-]{1,61}[a-zA-Z0-9]$', bucket_name):\n        raise ValueError(\"Invalid bucket name\")\n    \n    # Load plugin configuration without manipulating sys.path\n    plugin_dir = os.path.join('/var/app/plugins', bucket_name)\n    plugin_dir = os.path.realpath(plugin_dir)\n    \n    # Ensure the resolved path is still under the expected base directory\n    base_dir = os.path.realpath('/var/app/plugins')\n    if not plugin_dir.startswith(base_dir + os.sep):\n        raise ValueError(\"Invalid plugin directory path\")\n    \n    if os.path.exists(plugin_dir):\n        # Load plugin config files (e.g., JSON/YAML) instead of executing Python modules\n        config_file = os.path.join(plugin_dir, 'plugin_config.json')\n        if os.path.isfile(config_file):\n            import json\n            with open(config_file, 'r') as f:\n                _plugin_config = json.load(f)\n    \n    # Use pre-imported trusted modules only - never from user-controlled paths\n    token = get_session_token()\n    s3_client = boto3.client('s3', aws_access_key_id=token['key'], aws_secret_access_key=token['secret'])\n    return s3_client"}