# Import Hijacking via sys.path Precedence

Language: Python
Severity: Critical
CWE: CWE-427

## Source
3

## Flow
3-4-5

## Sink
5

## Vulnerable Code
```python
import sys
import os
def load_cloud_credentials(bucket_name):
    config_dir = os.path.join('/tmp/user_uploads', bucket_name)
    sys.path.insert(0, config_dir)
    import boto3_config
    session = boto3_config.create_session()
    return session.get_credentials()
def sync_s3_data(bucket):
    creds = load_cloud_credentials(bucket)
    print(f"Syncing {bucket} with credentials: {creds['access_key']}")
    return creds
```

## Explanation

The function accepts a user-controlled bucket_name parameter and directly inserts it into sys.path without validation. This allows an attacker to inject a malicious boto3_config.py module that will be imported, leading to arbitrary code execution when the import statement is reached.

## Remediation

The fix eliminates the import hijacking vulnerability by: (1) removing all manipulation of sys.path, (2) loading configuration modules only from a trusted system directory (/etc/app/bucket_configs) using importlib.util with explicit file paths and path traversal checks, and (3) strictly validating the bucket_name input against AWS S3 naming conventions to prevent directory traversal or injection attacks.

## Secure Code
```python
import os
import re
import importlib.util
import hashlib

ALLOWED_BUCKET_PATTERN = re.compile(r'^[a-z0-9][a-z0-9.\-]{1,61}[a-z0-9]$')
TRUSTED_CONFIG_DIR = '/etc/app/bucket_configs'

def _validate_bucket_name(bucket_name):
    """Validate bucket name follows AWS S3 naming conventions."""
    if not bucket_name or not ALLOWED_BUCKET_PATTERN.match(bucket_name):
        raise ValueError(f"Invalid bucket name: {bucket_name}")
    if '..' in bucket_name or '/' in bucket_name or '\\' in bucket_name:
        raise ValueError(f"Invalid characters in bucket name: {bucket_name}")
    return bucket_name

def _load_config_module(config_path):
    """Safely load a configuration module from an explicit file path without modifying sys.path."""
    if not os.path.isfile(config_path):
        raise FileNotFoundError(f"Configuration file not found: {config_path}")
    
    # Resolve the path and ensure it stays within the trusted directory
    resolved_path = os.path.realpath(config_path)
    trusted_resolved = os.path.realpath(TRUSTED_CONFIG_DIR)
    if not resolved_path.startswith(trusted_resolved + os.sep):
        raise PermissionError(f"Configuration file is outside trusted directory: {resolved_path}")
    
    spec = importlib.util.spec_from_file_location("boto3_config", resolved_path)
    if spec is None or spec.loader is None:
        raise ImportError(f"Cannot load module from: {resolved_path}")
    
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

def load_cloud_credentials(bucket_name):
    """Load AWS credentials from a trusted, validated configuration module."""
    validated_bucket = _validate_bucket_name(bucket_name)
    config_path = os.path.join(TRUSTED_CONFIG_DIR, validated_bucket, 'boto3_config.py')
    
    boto3_config = _load_config_module(config_path)
    
    if not hasattr(boto3_config, 'create_session') or not callable(boto3_config.create_session):
        raise AttributeError("Configuration module missing required 'create_session' function")
    
    session = boto3_config.create_session()
    return session.get_credentials()

def sync_s3_data(bucket):
    """Sync S3 data using validated bucket credentials."""
    creds = load_cloud_credentials(bucket)
    print(f"Syncing {bucket} with credentials: {creds['access_key']}")
    return creds
```
