# How Security Measures Protect API Keys and Sensitive Data in AI Hedge Fund

> Discover how the AI Hedge Fund project secures API keys and sensitive data using a defense-in-depth strategy. Learn about runtime injection and active status checks.

- Repository: [Virat Singh/ai-hedge-fund](https://github.com/virattt/ai-hedge-fund)
- Tags: best-practices
- Published: 2026-03-09

---

**The AI Hedge Fund project implements a defense-in-depth strategy that keeps API keys out of source code, injects them at runtime via environment variables, and enforces active-status checks through repository and service layers.**

The virattt/ai-hedge-fund repository handles sensitive financial data and third-party API credentials, making robust security architecture essential. The project employs multiple security measures to protect API keys and sensitive data, ensuring credentials never appear in version control while maintaining secure runtime access through layered abstraction.

## Environment-Level Protection

### Template-Based Configuration

The repository prevents accidental credential commits by using `.env.example` as a template. This file lists required variables with placeholder values like "your-api-key-here", prompting users to create their own local `.env` file that is excluded from version control.

### Runtime Environment Injection

When the application requires third-party access, it reads variables at runtime using `os.getenv`. In [`src/tools/api.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/tools/api.py), the `get_prices` function retrieves `FINANCIAL_DATASETS_API_KEY` from the environment and injects it into request headers without ever hardcoding the value.

```python
import os
from src.tools.api import get_prices

def get_daily_prices(ticker, start, end):
    # The function reads FINANCIAL_DATASETS_API_KEY from the environment

    prices = get_prices(ticker, start, end)
    return prices

```

*Source:* [src/tools/api.py – get_prices function](https://github.com/virattt/ai-hedge-fund/blob/main/src/tools/api.py#L60-L73)

## State-Based Key Retrieval

### Secure Extraction from Request State

For backend operations, the request object carries an `api_keys` dictionary populated from the database. The helper function `get_api_key_from_state` in [`src/utils/api_key.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py) extracts specific keys without exposing them to broader scope.

```python
from src.utils.api_key import get_api_key_from_state

def some_agent(state):
    # Pull the Financial Datasets key from the state payload

    api_key = get_api_key_from_state(state, "FINANCIAL_DATASETS_API_KEY")
    # Use the key to call the API (no secret appears in source)

    return fetch_some_data(api_key)

```

*Source:* [src/utils/api_key.py](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py)

## Database Security Architecture

### Encrypted Storage Model

API keys are stored in the `api_keys` table defined in [`app/backend/database/models.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/database/models.py). The model uses a `Text` column type with placeholder support for encryption, ensuring keys are not stored in plain text when encryption is enabled.

### Lifecycle Management Fields

The database schema includes `is_active` and `last_used` fields for operational control. These fields enable key rotation, revocation, and usage tracking without deleting records, maintaining comprehensive audit trails.

## Service and Repository Safeguards

### Active Key Filtering

The `ApiKeyService` in [`app/backend/services/api_key_service.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/services/api_key_service.py) fetches only active keys and returns a clean `{provider: key}` mapping. The service layer never logs key values, preventing accidental exposure in application logs.

```python
from app.backend.services.api_key_service import ApiKeyService
from app.backend.database.connection import get_db

def inject_keys_into_request(request):
    service = ApiKeyService(db=get_db())
    # Returns {"FINANCIAL_DATASETS_API_KEY": "...", "OPENAI_API_KEY": "..."}

    request.api_keys = service.get_api_keys_dict()

```

*Source:* [app/backend/services/api_key_service.py](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/services/api_key_service.py)

### Soft Deletion and Uniqueness Enforcement

The `ApiKeyRepository` in [`app/backend/repositories/api_key_repository.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/repositories/api_key_repository.py) enforces uniqueness constraints and implements soft deletion via `deactivate_api_key`. All CRUD operations pass through this layer, centralizing validation and preventing duplicate or revoked key usage.

```python
def get_api_key_by_provider(self, provider: str) -> Optional[ApiKey]:
    # Filters on is_active == True

    return self.db.query(ApiKey).filter(
        ApiKey.provider == provider,
        ApiKey.is_active == True
    ).first()

```

*Source:* [app/backend/repositories/api_key_repository.py – get_api_key_by_provider](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/repositories/api_key_repository.py#L48-L53)

## Operational Security Controls

### Preventing Log Exposure

The codebase strictly avoids logging sensitive headers. In [`src/tools/api.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/tools/api.py), only generic status messages like "Rate limited (429)" appear in print statements, ensuring API keys never leak through logging mechanisms.

### Controlled Endpoint Access

Backend routes in [`app/backend/routes/hedge_fund.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/routes/hedge_fund.py) and [`app/backend/routes/api_keys.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/routes/api_keys.py) require the `api_keys` dictionary to be supplied by authenticated clients. The database service validates that only active, authorized keys are used for financial data operations.

## Key Security Files

| File | Role in Security |
|------|------------------|
| `.env.example` | Template for local secret configuration |
| [`src/utils/api_key.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/utils/api_key.py) | Helper for secure state-based key extraction |
| [`src/tools/api.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/tools/api.py) | Runtime environment injection |
| [`app/backend/services/api_key_service.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/services/api_key_service.py) | Active key filtering and clean mapping |
| [`app/backend/repositories/api_key_repository.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/repositories/api_key_repository.py) | Uniqueness and soft-deletion enforcement |
| [`app/backend/database/models.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/database/models.py) | Encrypted storage schema with lifecycle fields |

## Summary

- Environment variables prevent hardcoding secrets in version control
- State-based retrieval isolates keys within request scope
- Database encryption and lifecycle fields enable secure storage and rotation
- Service and repository layers enforce active-status validation and prevent logging exposure
- Endpoint controls ensure only authorized, active keys access financial data

## Frequently Asked Questions

### How does the project prevent API keys from being committed to Git?

The repository uses `.env.example` as a template with placeholder values, while the actual `.env` file containing secrets is excluded from version control. All runtime access uses `os.getenv`, ensuring no literal keys exist in source code.

### What happens when an API key is revoked or expires?

The `ApiKeyRepository` implements soft deletion through `deactivate_api_key`, setting `is_active` to false. The `ApiKeyService` filters for active keys only, preventing revoked credentials from being injected into requests.

### Are API keys encrypted in the database?

The `ApiKey` model in [`app/backend/database/models.py`](https://github.com/virattt/ai-hedge-fund/blob/main/app/backend/database/models.py) uses a `Text` column type with placeholder support for encryption. While the base implementation stores keys as text, the architecture supports transparent encryption at the database or application layer.

### How does the application prevent API keys from appearing in logs?

The codebase strictly avoids logging request headers containing credentials. In [`src/tools/api.py`](https://github.com/virattt/ai-hedge-fund/blob/main/src/tools/api.py), only generic status messages like "Rate limited (429)" are printed, and the `ApiKeyService` never logs the `{provider: key}` mapping it returns.