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>
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:
- Compromised federated instance attempts to query credentials
- Malicious actor sends credential-related commands
- Accidental credential exposure via federation messages
- 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-credentialsTransit 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:
- Credential Query Attempts: Alert when credential queries are blocked
- Transit Key Usage: Monitor
mosaic-credentialsdecrypt operations - Federation Message Volume: Detect abnormal query patterns
- 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:
-
Immediate Actions:
- Suspend affected federation connections
- Rotate all potentially exposed credentials
- Review audit logs for compromise indicators
-
Investigation:
- Check QueryService/CommandService logs for blocked attempts
- Verify Transit key integrity via OpenBao audit logs
- Analyze federation message payloads for credential data
-
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) |