Encrypt LLM provider API keys in database #359

Closed
opened 2026-02-07 17:12:41 +00:00 by jason.woltje · 0 comments
Owner

Phase 5a - LLM Provider API Key Encryption

Problem

LlmProviderInstance.config is a JSON field that contains apiKey in plaintext. If the database is compromised, all LLM provider API keys (OpenAI, Claude, etc.) are exposed.

Requirements

  1. Create Prisma middleware to transparently encrypt/decrypt the apiKey field within the config JSON
  2. Write data migration script for existing plaintext API keys
  3. Use VaultService with TransitKey.LLM_CONFIG for encryption

Implementation Notes

  • The config field is typed as Json in Prisma, containing provider-specific configuration
  • Only the apiKey field within the JSON should be encrypted, other config fields remain readable
  • Middleware intercepts LlmProviderInstance create/update to encrypt config.apiKey
  • Middleware intercepts read operations to decrypt config.apiKey
  • Auto-detect: if config.apiKey starts with vault: or aes:, it's encrypted; otherwise plaintext (legacy)
  • Data migration: iterate all LlmProviderInstance rows, encrypt apiKey in config JSON
  • LlmManagerService at apps/api/src/llm/llm-manager.service.ts needs to work with decrypted keys

Files

  • apps/api/src/prisma/llm-encryption.middleware.ts (new)
  • apps/api/src/prisma/llm-encryption.middleware.spec.ts (new)
  • apps/api/src/prisma/prisma.service.ts (modify - register middleware)
  • apps/api/src/llm/llm-manager.service.ts (modify - verify works with decrypted keys)
  • apps/api/prisma/migrations/[timestamp]_encrypt_llm_api_keys/ (new - data migration)

Acceptance Criteria

  • New LLM provider API keys encrypted before storage
  • Existing plaintext keys decrypted correctly (backward compatible)
  • Data migration encrypts all existing plaintext API keys
  • LLM provider functionality works correctly with encrypted keys
  • Unit tests for middleware logic

Dependencies

  • Depends on: VaultService (Phase 2b)

Refs #346

## Phase 5a - LLM Provider API Key Encryption ### Problem LlmProviderInstance.config is a JSON field that contains apiKey in plaintext. If the database is compromised, all LLM provider API keys (OpenAI, Claude, etc.) are exposed. ### Requirements 1. Create Prisma middleware to transparently encrypt/decrypt the apiKey field within the config JSON 2. Write data migration script for existing plaintext API keys 3. Use VaultService with TransitKey.LLM_CONFIG for encryption ### Implementation Notes - The config field is typed as Json in Prisma, containing provider-specific configuration - Only the apiKey field within the JSON should be encrypted, other config fields remain readable - Middleware intercepts LlmProviderInstance create/update to encrypt config.apiKey - Middleware intercepts read operations to decrypt config.apiKey - Auto-detect: if config.apiKey starts with vault: or aes:, it's encrypted; otherwise plaintext (legacy) - Data migration: iterate all LlmProviderInstance rows, encrypt apiKey in config JSON - LlmManagerService at apps/api/src/llm/llm-manager.service.ts needs to work with decrypted keys ### Files - apps/api/src/prisma/llm-encryption.middleware.ts (new) - apps/api/src/prisma/llm-encryption.middleware.spec.ts (new) - apps/api/src/prisma/prisma.service.ts (modify - register middleware) - apps/api/src/llm/llm-manager.service.ts (modify - verify works with decrypted keys) - apps/api/prisma/migrations/[timestamp]_encrypt_llm_api_keys/ (new - data migration) ### Acceptance Criteria - [ ] New LLM provider API keys encrypted before storage - [ ] Existing plaintext keys decrypted correctly (backward compatible) - [ ] Data migration encrypts all existing plaintext API keys - [ ] LLM provider functionality works correctly with encrypted keys - [ ] Unit tests for middleware logic ### Dependencies - Depends on: VaultService (Phase 2b) Refs #346
jason.woltje added this to the M9-CredentialSecurity (0.0.9) milestone 2026-02-07 17:12:41 +00:00
jason.woltje added the securityapiapip1 labels 2026-02-07 17:12:41 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaic/stack#359