# Import Hijacking via sys.path Precedence

Language: Python
Severity: Critical
CWE: CWE-426

## Source
5

## Flow
5-6-7

## Sink
6, 7

## Vulnerable Code
```python
import sys
import os
def load_ml_model_config(workspace_dir):
    model_path = os.path.join(workspace_dir, 'models')
    sys.path.insert(0, model_path)
    import tensorflow_utils
    import numpy_helpers
    config = tensorflow_utils.load_hyperparameters()
    data = numpy_helpers.preprocess_tensor(config['input_shape'])
    return {'model_config': config, 'preprocessed': data}
def deploy_inference_endpoint(user_workspace):
    return load_ml_model_config(user_workspace)
```

## Explanation

The code inserts a user-controlled workspace directory at the beginning of sys.path (line 5), then imports modules (lines 6-7) which Python will search for in that user-controlled path first. An attacker can place malicious tensorflow_utils.py or numpy_helpers.py files in their workspace to execute arbitrary code during import.

## Remediation

The fix eliminates sys.path manipulation entirely by using importlib.util to load modules directly from validated file paths. It enforces that the workspace directory resides within a trusted root directory (preventing arbitrary path injection), validates module names against an allowlist, and checks for path traversal attacks before loading any module file.

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

ALLOWED_MODULES = {'tensorflow_utils', 'numpy_helpers'}
TRUSTED_WORKSPACE_ROOT = '/opt/ml/workspaces'

def _validate_workspace_path(workspace_dir):
    """Ensure workspace directory is within the trusted root and properly sanitized."""
    real_workspace = os.path.realpath(workspace_dir)
    real_trusted_root = os.path.realpath(TRUSTED_WORKSPACE_ROOT)
    if not real_workspace.startswith(real_trusted_root + os.sep):
        raise ValueError(f"Workspace directory must be within {TRUSTED_WORKSPACE_ROOT}")
    return real_workspace

def _safe_import_from_path(module_name, directory):
    """Safely import a specific module from a specific directory without modifying sys.path."""
    if module_name not in ALLOWED_MODULES:
        raise ImportError(f"Module '{module_name}' is not in the allowed module list.")
    
    module_file = os.path.join(directory, f"{module_name}.py")
    real_module_file = os.path.realpath(module_file)
    real_directory = os.path.realpath(directory)
    
    # Prevent path traversal in module resolution
    if not real_module_file.startswith(real_directory + os.sep):
        raise ImportError(f"Module path traversal detected for '{module_name}'.")
    
    if not os.path.isfile(real_module_file):
        raise ImportError(f"Module '{module_name}' not found in {directory}.")
    
    spec = importlib.util.spec_from_file_location(module_name, real_module_file)
    if spec is None or spec.loader is None:
        raise ImportError(f"Cannot load module spec for '{module_name}'.")
    
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

def load_ml_model_config(workspace_dir):
    """Load ML model configuration from a validated workspace directory."""
    validated_workspace = _validate_workspace_path(workspace_dir)
    model_path = os.path.join(validated_workspace, 'models')
    
    if not os.path.isdir(model_path):
        raise FileNotFoundError(f"Models directory not found in workspace: {model_path}")
    
    # Import modules directly from the validated path without modifying sys.path
    tensorflow_utils = _safe_import_from_path('tensorflow_utils', model_path)
    numpy_helpers = _safe_import_from_path('numpy_helpers', model_path)
    
    config = tensorflow_utils.load_hyperparameters()
    data = numpy_helpers.preprocess_tensor(config['input_shape'])
    return {'model_config': config, 'preprocessed': data}

def deploy_inference_endpoint(user_workspace):
    """Deploy an inference endpoint using configuration from the user's workspace."""
    return load_ml_model_config(user_workspace)
```
