# MS22 Phase 1 Module Audit Date: 2026-03-01 Branch: `fix/ms22-audit` Scope: - `apps/api/src/container-lifecycle/` - `apps/api/src/crypto/` - `apps/api/src/agent-config/` - `apps/api/src/onboarding/` - `apps/api/src/fleet-settings/` - `apps/api/src/chat-proxy/` ## Summary Audit completed for module wiring, security controls, input validation, and error handling. Findings: 1. `chat-proxy`: raw internal/upstream error messages were returned to clients over SSE (fixed). 2. `chat-proxy`: proxy requests to OpenClaw did not forward the container bearer token returned by lifecycle startup (fixed). 3. `agent-config`: token validation returned early and used length-gated compare logic, creating avoidable timing side-channel behavior (hardened). ## Module Review Results ### 1) `container-lifecycle` - NestJS module dependency audit: - `ContainerLifecycleModule` imports `ConfigModule`, `PrismaModule`, and `CryptoModule` required by `ContainerLifecycleService`. - Providers/exports are correct (`ContainerLifecycleService` provided and exported). - Security review: - Container operations are user-scoped by `userId` and do not expose cross-user selectors in this module. - AES token generation/decryption delegated to `CryptoService`. - Input validation: - No controller endpoints in this module; no direct request DTO surface here. - Error handling: - No direct HTTP layer here; errors flow to callers/global filter. - Finding status: **No issues found in this module**. ### 2) `crypto` - NestJS module dependency audit: - `CryptoModule` correctly imports `ConfigModule` for `ConfigService`. - `CryptoService` is correctly provided/exported. - Security review: - AES-256-GCM is implemented correctly. - 96-bit IV generated via `randomBytes(12)` per encryption. - Auth tag captured and verified on decrypt (`setAuthTag` + `decipher.final()`). - HKDF derives a fixed 32-byte key from `MOSAIC_SECRET_KEY`. - Input validation: - No DTO/request surface in this module. - Error handling: - Decrypt failures are normalized to `Failed to decrypt value`. - Finding status: **No issues found in this module**. ### 3) `agent-config` - NestJS module dependency audit: - `AgentConfigModule` imports `PrismaModule` + `CryptoModule`; `AgentConfigService` and `AgentConfigGuard` are provided. - Controller/guard/service wiring is correct. - Security review: - Bearer token comparisons used `timingSafeEqual`, but returned early on first match and performed length-gated comparison. - Internal route (`/api/internal/agent-config/:id`) is access-controlled by bearer token guard and container-id match (`containerAuth.id === :id`). - Input validation: - Header token extraction and route param are manually handled (no DTO for `:id`, acceptable for current use but should remain constrained). - Error handling: - Service throws typed Nest exceptions for not-found paths. - Finding status: **Issue found and fixed**. ### 4) `onboarding` - NestJS module dependency audit: - `OnboardingModule` imports required dependencies (`PrismaModule`, `CryptoModule`; `ConfigModule` currently unused but harmless). - Providers/controllers are correctly declared. - Security review: - `OnboardingGuard` blocks all mutating onboarding routes once `onboarding.completed=true`. - Onboarding cannot be re-run via guarded endpoints after completion. - Input validation: - DTOs use `class-validator` decorators for all request bodies. - Error handling: - Uses typed Nest exceptions (`ConflictException`, `BadRequestException`). - Finding status: **No issues found in this module**. ### 5) `fleet-settings` - NestJS module dependency audit: - `FleetSettingsModule` imports `AuthModule`, `PrismaModule`, `CryptoModule` required by its controller/service. - Provider/export wiring is correct for `FleetSettingsService`. - Security review: - Class-level `AuthGuard` protects all routes. - Admin-only routes additionally use `AdminGuard` (`oidc` and `breakglass/reset-password`). - Provider list/get responses do not expose `apiKey`. - OIDC read response intentionally omits `clientSecret`. - Input validation: - DTOs are decorated with `class-validator`. - Error handling: - Ownership/not-found conditions use typed exceptions. - Finding status: **No issues found in this module**. ### 6) `chat-proxy` - NestJS module dependency audit: - `ChatProxyModule` imports `AuthModule`, `PrismaModule`, `ContainerLifecycleModule` needed by controller/service. - Provider/controller wiring is correct. - Security review: - User identity comes from `AuthGuard`; no user-provided container selector, so no cross-user container proxy path found. - **Issue fixed:** gateway bearer token was not forwarded on proxied requests. - **Issue fixed:** SSE error events exposed raw internal exception messages. - Input validation: - `ChatStreamDto` + nested `ChatMessageDto` use `class-validator` decorators. - Error handling: - **Issue fixed:** controller now emits safe client error messages and logs details server-side. - Finding status: **Issues found and fixed**. ## Security Checklist Outcomes - `fleet-settings`: admin-only routes are guarded; non-admin users cannot access OIDC or breakglass reset routes. Provider secrets are not returned in provider read endpoints. - `agent-config`: token comparison hardened; route remains gated by bearer token + container id binding. - `onboarding`: guarded mutating endpoints cannot run after completion. - `crypto`: AES-256-GCM usage is correct (random IV, auth-tag verification, fixed 32-byte key derivation). - `chat-proxy`: user cannot target another user’s container; proxy now authenticates to OpenClaw using per-container bearer token. ## Input Validation - DTO coverage is present in onboarding, fleet-settings, and chat-proxy request bodies. - No critical unvalidated body inputs found in scoped modules. ## Error Handling - Global API layer has a sanitizing `GlobalExceptionFilter`. - `chat-proxy` used manual response handling (`@Res`) and bypassed global filter; this was corrected by sending safe generic SSE errors. - No additional critical sensitive-data leaks found in reviewed scope. ## Changes Made 1. Hardened token comparison behavior in: - `apps/api/src/agent-config/agent-config.service.ts` - Changes: - Compare SHA-256 digests with `timingSafeEqual`. - Avoid early return during scan to reduce timing signal differences. 2. Fixed OpenClaw auth forwarding and error leak risk in: - `apps/api/src/chat-proxy/chat-proxy.service.ts` - `apps/api/src/chat-proxy/chat-proxy.controller.ts` - `apps/api/src/chat-proxy/chat-proxy.service.spec.ts` - Changes: - Forward `Authorization: Bearer ` when proxying chat requests. - Stop returning raw internal/upstream error text to clients over SSE. - Log details server-side and return safe client-facing messages. ## Validation Commands Required quality gate command run: - `pnpm turbo lint typecheck --filter=@mosaic/api` (Results captured in session logs.)