Resolve FRE-5199: silent run review for CEO -- FRE-5198 done, FRE-660 unblocked

This commit is contained in:
2026-05-12 17:23:27 -04:00
parent cd45f5dbdf
commit 82fcb59ff6
7 changed files with 399 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
# Security Review: FRE-4806 — Datadog APM + Sentry Error Tracking Integration
**Reviewer:** Security Reviewer
**Date:** 2026-05-12
**Scope:** Runtime security — env var secrets, network egress, API key handling, data exposure
**Files Reviewed:**
- `packages/monitoring/src/config.ts`
- `packages/monitoring/src/sentry.ts`
- `packages/monitoring/src/datadog.ts`
- `packages/monitoring/src/datadog-init.ts`
- `packages/monitoring/src/datadog-logs.ts`
- `packages/monitoring/src/cloudwatch.ts`
- `packages/api/src/middleware/auth.middleware.ts`
- `packages/api/src/middleware/monitoring.middleware.ts`
- `packages/api/src/middleware/error-handling.middleware.ts`
- `packages/api/src/server.ts`
- `packages/api/src/index.ts`
---
## P1 Findings (Resolved)
### P1 #1 — API key leaked to Sentry as user ID ✅ FIXED
**File:** `auth.middleware.ts:49-52`
**Finding:** Raw API key stored in `user.id`, passed to `setSentryUser()` on 5xx errors.
**Fix:** Key truncated to `api-{first-8-chars}...` before assignment. Verified `error-handling.middleware.ts:29-30` reads from `user.id` (truncated), not `authReq.apiKey` (raw).
### P1 #2 — DD_API_KEY missing from Zod schema ✅ FIXED
**File:** `config.ts:10-11`
**Finding:** `DD_API_KEY` consumed in `datadog-logs.ts` but not validated in schema.
**Fix:** Added `DD_API_KEY: z.string().default('')` and `DD_SITE: z.string().default('datadoghq.com')` to schema and parse call.
---
## P2 Findings (Hardening Recommendations — non-blocking)
### P2 #1 — No circuit breaker on Datadog log forwarding
**File:** `datadog-logs.ts:17-44`
**Risk:** Every `forwardLog()` call does async `fetch()` with no timeout. Slow intake API holds open connections.
**Recommendation:** Add `AbortSignal.timeout(5000)` to fetch; consider simple circuit breaker.
### P2 #2 — dd-trace sample rate defaults to 100%
**File:** `config.ts:8`
**Risk:** `DD_TRACE_SAMPLE_RATE` defaults to `1.0`. High production traffic = full span volume to Datadog.
**Recommendation:** Default to `0.1`; override via env for development.
### P2 #3 — CloudWatch rate limit not enforced
**File:** `cloudwatch.ts:46-56`, `monitoring.middleware.ts:46`
**Risk:** CloudWatch allows 5 TPS per metric/region. `emitError` on 5xx adds second call per request.
**Recommendation:** Add in-memory batching or token bucket rate limiter.
### P2 #4 — Sentry beforeSend: pathname exposes resource IDs
**File:** `sentry.ts:28-33`
**Risk:** Query strings stripped, but path segments like `/api/v1/users/42/orders` expose resource IDs.
**Recommendation:** Regex-based path masking for sensitive routes.
---
## P3 Findings (Low Priority — non-blocking)
### P3 #1 — Error response leaks internal error name/message to client
**File:** `error-handling.middleware.ts:18-25`
**Risk:** `err.name` and `err.message` returned directly in JSON response.
**Recommendation:** Generic messages for 5xx; keep details in logs only.
### P3 #2 — AWS credential chain not explicit
**File:** `cloudwatch.ts:10`
**Risk:** `CloudWatchClient` uses default credential chain; may pick up `~/.aws/credentials` locally.
**Recommendation:** Document expected credential source per environment.
### P3 #3 — Sentry DSN empty default fails open in production
**File:** `config.ts:14`
**Risk:** Empty `SENTRY_DSN` silently disables error tracking in production.
**Recommendation:** Startup health check warning when `DD_ENV === "production"` and DSN is empty.
---
## Verdict: ✅ SECURITY PASS
**Both P1 findings remediated and verified.** The 4 P2 and 3 P3 findings are hardening recommendations suitable for follow-up child issues if the team desires. No blocking security vulnerabilities remain.
**Disposition:** Issue approved for merge.