# Import Hijacking via sys.path Precedence

Language: Python
Severity: Critical
CWE: CWE-427

## Source
3

## Flow
3-4-6

## Sink
6

## Vulnerable Code
```python
import sys
import os
def load_cloud_credentials(bucket_name):
    plugin_dir = os.path.join('/var/app/plugins', bucket_name)
    if os.path.exists(plugin_dir):
        sys.path.insert(0, plugin_dir)
    import boto3
    from aws_config import get_session_token
    token = get_session_token()
    s3_client = boto3.client('s3', aws_access_key_id=token['key'], aws_secret_access_key=token['secret'])
    return s3_client
def fetch_encrypted_data(bucket, object_key):
    client = load_cloud_credentials(bucket)
    response = client.get_object(Bucket=bucket, Key=object_key)
    return response['Body'].read()
```

## Explanation

The bucket_name parameter is user-controlled and used to construct a directory path that gets prepended to sys.path. This allows an attacker to inject malicious boto3 or aws_config modules that will be imported before legitimate ones, enabling credential theft or code execution when the imports occur on lines 7-8.

## Remediation

The fix removes the dangerous sys.path.insert() call entirely and instead uses top-level imports of boto3 and aws_config, preventing any user-controlled directory from influencing module resolution. Additionally, strict input validation is applied to bucket_name using a regex matching valid S3 bucket naming conventions, and a realpath check ensures the resolved plugin directory cannot escape the approved base path via symlinks or traversal.

## Secure Code
```python
import sys
import os
import re
import importlib
import boto3
from aws_config import get_session_token

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

def load_cloud_credentials(bucket_name):
    # Validate bucket_name against AWS S3 bucket naming rules to prevent path traversal
    if not bucket_name or not ALLOWED_BUCKET_PATTERN.match(bucket_name):
        raise ValueError(f"Invalid bucket name: {bucket_name}")
    
    # Ensure no path traversal components
    if '..' in bucket_name or '/' in bucket_name or '\\' in bucket_name:
        raise ValueError(f"Invalid bucket name contains path traversal characters: {bucket_name}")
    
    plugin_dir = os.path.join(APPROVED_PLUGIN_BASE, bucket_name)
    
    # Resolve to absolute path and verify it's still under the approved base
    resolved_path = os.path.realpath(plugin_dir)
    approved_base_resolved = os.path.realpath(APPROVED_PLUGIN_BASE)
    if not resolved_path.startswith(approved_base_resolved + os.sep):
        raise ValueError(f"Plugin directory escapes approved base path: {bucket_name}")
    
    # Do NOT modify sys.path - use top-level imports of boto3 and aws_config instead
    # If bucket-specific configuration is needed, load only data files (not Python modules)
    token = get_session_token()
    s3_client = boto3.client('s3', aws_access_key_id=token['key'], aws_secret_access_key=token['secret'])
    return s3_client

def fetch_encrypted_data(bucket, object_key):
    client = load_cloud_credentials(bucket)
    response = client.get_object(Bucket=bucket, Key=object_key)
    return response['Body'].read()
```
