Files
stack/docs/security/federation-credential-isolation.md
Jason Woltje 73074932f6 feat(#360): Add federation credential isolation
Implement explicit deny-lists in QueryService and CommandService to prevent
user credentials from leaking across federation boundaries.

## Changes

### Core Implementation
- QueryService: Block all credential-related queries with keyword detection
- CommandService: Block all credential operations (create/update/delete/read)
- Case-insensitive keyword matching for both queries and commands

### Security Features
- Deny-list includes: credential, api_key, secret, token, password, oauth
- Errors returned for blocked operations
- No impact on existing allowed operations (tasks, events, projects, agent commands)

### Testing
- Added 2 unit tests to query.service.spec.ts
- Added 3 unit tests to command.service.spec.ts
- Added 8 integration tests in credential-isolation.integration.spec.ts
- All 377 federation tests passing

### Documentation
- Created comprehensive security doc at docs/security/federation-credential-isolation.md
- Documents 4 security guarantees (G1-G4)
- Includes testing strategy and incident response procedures

## Security Guarantees

1. G1: Credential Confidentiality - Credentials never leave instance in plaintext
2. G2: Cross-Instance Isolation - Compromised key on one instance doesn't affect others
3. G3: Query/Command Isolation - Federated instances cannot query/modify credentials
4. G4: Accidental Exposure Prevention - Credentials cannot leak via messages

## Defense-in-Depth

This implementation adds application-layer protection on top of existing:
- Transit key separation (mosaic-credentials vs mosaic-federation)
- Per-instance OpenBao servers
- Workspace-scoped credential access

Fixes #360

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 16:55:49 -06:00

7.5 KiB

Federation Credential Isolation

Overview

This document describes the security guarantees preventing user credentials from leaking across federation boundaries in Mosaic Stack.

Threat Model

Attack Scenarios:

  1. Compromised federated instance attempts to query credentials
  2. Malicious actor sends credential-related commands
  3. Accidental credential exposure via federation messages
  4. Transit key compromise on one instance

Defense-in-Depth Architecture

Mosaic Stack implements multiple layers of protection to prevent credential leakage:

Layer 1: Cryptographic Isolation

Separate Transit Keys:

  • mosaic-credentials: Used exclusively for user credentials (API keys, OAuth tokens, secrets)
  • mosaic-federation: Used exclusively for federation private keys
  • Key Management: Each key has independent lifecycle and access controls

Per-Instance OpenBao:

  • Each federated instance runs its own OpenBao server
  • Transit keys are not shared between instances
  • Even if one instance's Transit key is compromised, credentials on other instances remain protected

Result: Credentials encrypted with mosaic-credentials on Instance A cannot be decrypted by compromised mosaic-credentials key on Instance B, as they are completely separate keys on separate OpenBao instances.

Layer 2: Application-Layer Deny-Lists

Query Service Isolation:

// QueryService blocks all credential-related queries
private isCredentialQuery(query: string): boolean {
  const credentialKeywords = [
    "credential",
    "user_credential",
    "api_key",
    "secret",
    "token",
    "password",
    "oauth",
    "access_token",
  ];
  return credentialKeywords.some(k => query.toLowerCase().includes(k));
}

Command Service Isolation:

// CommandService blocks all credential operations
private isCredentialCommand(commandType: string): boolean {
  const credentialPrefixes = ["credential.", "credentials."];
  return credentialPrefixes.some(p => commandType.toLowerCase().startsWith(p));
}

Blocked Operations:

  • SELECT * FROM user_credentials
  • credential.create
  • credential.update
  • credential.delete
  • credential.read
  • credentials.list

Allowed Operations:

  • Task queries
  • Event queries
  • Project queries
  • Agent spawn commands

Layer 3: Message Payload Verification

Federation Messages:

  • Query messages: Only contain query string and workspace context
  • Command messages: Only contain command type and non-credential payload
  • Event messages: Only contain event type and metadata

No Plaintext Credentials:

  • Federation messages NEVER contain credential plaintext
  • Credentials are encrypted at rest with mosaic-credentials Transit key
  • Credentials are only decrypted within the owning instance

Layer 4: Workspace Isolation

Row-Level Security (RLS):

  • UserCredential table enforces per-workspace isolation
  • Federation queries require explicit workspace context
  • Cross-workspace credential access is prohibited

Access Control:

-- UserCredential model
model UserCredential {
  userId      String
  workspaceId String?  // Nullable for user-scope credentials
  scope       CredentialScope  // USER | WORKSPACE | SYSTEM

  @@unique([userId, workspaceId, provider, name])
  @@index([workspaceId])
}

Security Guarantees

G1: Credential Confidentiality

Guarantee: User credentials never leave the owning instance in plaintext or decryptable form.

Enforcement:

  • Transit encryption with per-instance keys
  • Application-layer deny-lists
  • No credential data in federation messages

Verification: Integration tests in credential-isolation.integration.spec.ts

G2: Cross-Instance Isolation

Guarantee: Compromised Transit key on Instance A cannot decrypt credentials on Instance B.

Enforcement:

  • Each instance has independent OpenBao server
  • Transit keys are not shared or synchronized
  • No mechanism for cross-instance key access

Verification: Architectural design + infrastructure separation

G3: Query/Command Isolation

Guarantee: Federated instances cannot query or modify credentials on remote instances.

Enforcement:

  • QueryService deny-list blocks credential queries
  • CommandService deny-list blocks credential operations
  • Errors returned for blocked operations

Verification: Unit tests in query.service.spec.ts and command.service.spec.ts

G4: Accidental Exposure Prevention

Guarantee: Credentials cannot accidentally leak via federation messages.

Enforcement:

  • Message payloads explicitly exclude credential data
  • Serialization logic filters credential fields
  • Type system prevents credential inclusion

Verification: Message type definitions + code review

Testing

Unit Tests

pnpm --filter @mosaic/api test query.service.spec
pnpm --filter @mosaic/api test command.service.spec

Coverage:

  • Credential query blocking
  • Credential command blocking
  • Case-insensitive keyword matching
  • Valid operation allowance

Integration Tests

pnpm --filter @mosaic/api test credential-isolation.integration.spec

Coverage:

  • End-to-end query isolation
  • End-to-end command isolation
  • Multi-case keyword variants
  • Architecture documentation tests

Manual Verification

Test Scenario: Attempt Credential Query

# From remote instance, send query
curl -X POST https://instance-a.example.com/api/v1/federation/incoming/query \
  -H "Content-Type: application/json" \
  -d '{
    "messageId": "test-1",
    "instanceId": "instance-b",
    "query": "SELECT * FROM user_credentials",
    "context": {"workspaceId": "workspace-1"},
    "timestamp": 1234567890,
    "signature": "..."
  }'

# Expected Response:
# {
#   "success": false,
#   "error": "Credential queries are not allowed via federation"
# }

Monitoring & Alerting

Recommended Alerts:

  1. Credential Query Attempts: Alert when credential queries are blocked
  2. Transit Key Usage: Monitor mosaic-credentials decrypt operations
  3. Federation Message Volume: Detect abnormal query patterns
  4. OpenBao Health: Alert on OpenBao unavailability (falls back to local encryption)

Audit Logging:

// QueryService logs blocked credential queries
this.logger.warn(`Blocked credential query from ${instanceId}`, {
  messageId,
  query,
  timestamp: new Date(),
});

Incident Response

If Credential Exposure Suspected:

  1. Immediate Actions:

    • Suspend affected federation connections
    • Rotate all potentially exposed credentials
    • Review audit logs for compromise indicators
  2. Investigation:

    • Check QueryService/CommandService logs for blocked attempts
    • Verify Transit key integrity via OpenBao audit logs
    • Analyze federation message payloads for credential data
  3. Remediation:

    • Rotate all credentials in affected workspaces
    • Update deny-lists if new attack vector discovered
    • Re-establish federation connections after verification

References

  • Design Document: docs/design/credential-security.md
  • VaultService Implementation: apps/api/src/vault/vault.service.ts
  • QueryService Implementation: apps/api/src/federation/query.service.ts
  • CommandService Implementation: apps/api/src/federation/command.service.ts
  • Transit Keys: apps/api/src/vault/vault.constants.ts

Change Log

Date Version Change
2026-02-07 1.0 Initial documentation (Issue #360)