[LegalMind] isDevelopment is true when NODE_ENV is unset, exposing debug endpoints on misconfigured production deploys
In server/config/env.ts line 101, isDevelopment is derived as `getEnv('NODE_ENV') !== 'production'`. When NODE_ENV is accidentally unset or empty in production, isDevelopment be...
StateDoneNext ActionClosedOwnerLuciRuntimeClosedAge27d ago
Ticket is done; runtime is closed.·profile claude_opus_1m_medium · cwd /home/lucienne/workspace · uptime 27d 4h · last activity 27d 2h ago
Description
MC-3568
In server/config/env.ts line 101, isDevelopment is derived as `getEnv('NODE_ENV') !== 'production'`. When NODE_ENV is accidentally unset or empty in production, isDevelopment becomes true, exposing /api/session-debug (routes.ts:219) and /api/auth/debug (auth/index.ts:139) endpoints. These leak session IDs, cookie names, auth state, and environment variables. The env.ts code already warns about SESSION_SECRET, but NODE_ENV itself has no equivalent guard. validateEnv() should require NODE_ENV=production in non-Replit environments or warn loudly when it's unset.
File: server/config/env.ts:101
Complexity: medium
Found by: nightly code review (e49ba03c fix(MC-3526): scope role-phrase stripping to user instruction fields)
Activity
done
INTERACTIVE
Luci is working...
Details —
Done
· High
· Luci
▼
SState
Done
Closed
PPeople
TTiming / Details▼
legalmind-review (scheduled)
LegalMind
27d ago
27d ago
Advanced / Operator evidence
RRouting owner
ROperator console
Ticket is done; runtime is closed.completedprofile claude_opus_1m_medium · cwd /home/lucienne/workspace · uptime 27d 4h · last activity 27d 2h agoMC is visibility-only. Hermes Luci launches and gates work outside MC, then mirrors evidence/status here.
ce4a7322-391b-42cd-b9c0-6dc241fdae3f · luci · claude/anthropic/opus[1m]
WWorkflow
Start Dev Review + QA ▾
Select phases to include:
Agents
Review Gates
Decision
WAT routing: choose an agent, review gate, or decision. Buttons use the live runtime when one is attached.
Luci dispatching this ticket to Larry (background worker via SSH).
luci27d ago
Larry: Planning — reading ticket and env.ts to assess scopePROGRESS: Designing — fail-closed isDevelopment + require explicit NODE_ENV in non-Replit envsPROGRESS: Building — fail-closed isDevelopment + validateEnv NODE_ENV guardAcknowledged. Writing test now.PROGRESS: Testing — running new test and typecheckAll 8 tests pass. Let me run typecheck and adjacent existing env-touching tests.TypeScript errors are pre-existing and unrelated (documents.ts, driveFolders.ts). My change introduced no new TS errors. Adjacent NODE_ENV tests still pass.Pre-existing, unrelated. Committing.
Completed on Larry:
## Summary
Fixed MC-3568 by changing `isDevelopment` in `server/config/env.ts:101` from `getEnv('NODE_ENV') !== 'production'` (true when unset) to `=== 'development'` (fail-closed). Added `validateEnv()` warnings for unset or unrecognised NODE_ENV values in non-Replit environments. Wrote 8 regression tests covering unset/empty/dev/prod/unrecognised cases — all pass. Pre-existing TS errors in unrelated files are not from this change. Committed as `9ac50eb` and pushed to staging.
luci27d ago
Larry: Triggering post-completion code review...
luci27d ago
Code review (Larry reviewer via claude/opus):
n.
Coverage of the regression case (unset NODE_ENV → `
isDevelopment=false`) is explicit, the `validateEnv()` warning is appropriately scoped to non
-Replit envs, and the Replit code path is preserved via `isReplitEnvironment()` checks. No C
RITICAL or IMPORTANT issues.
VERDICT: PASS
Fail-closed fix is correct and well-tested; two stale-doc nits but no real breakage.
- MINOR: `server/config/env.ts:386-388` — docstring for `isDevEnvironment()` still says "NODE_ENV is not 'production'" and "Default to true if not production", but the body now returns `env.isDevelopment` (fail-closed). Behavior matches the fix; comment lies. Update for future readers.
- MINOR: `server/config/env.ts:103` — `nodeEnv: getEnv('NODE_ENV', 'development')` still defaults the *string* to `'development'` when unset, while `isDevelopment` is now `false` in the same case. Harmless (no code paths string-compare `env.nodeEnv` for dev gating that I see), but the inconsistency could mislead. Consider defaulting to `''` or `'unknown'`.
- MINOR: test file is truncated in the diff at the "staging" case — assumed complete in the repo; if the final `it(...)` block isn't closed, tests won't compile. Worth a local `npm test` confirmation.
Coverage of the regression case (unset NODE_ENV → `isDevelopment=false`) is explicit, the `validateEnv()` warning is appropriately scoped to non-Replit envs, and the Replit code path is preserved via `isReplitEnvironment()` checks. No CRITICAL or IMPORTANT issues.
VERDICT: PASS
luci27d ago
Larry shipped with clean code review. Auto-dispatching Luci-reviewer (verdict: clean). Next dispatch tick will spawn a single-session reviewer worker to verify, run Tessa subagent inline if UI-touching, merge the PR, and close.
luci27d ago
Completed:
DONE: Verified Larry's MC-3568 fix (9ac50eb) on LegalMind staging — `isDevelopment` is now fail-closed (`=== 'development'`), 8 regression tests pass. Addressed all 3 code-review MINOR nits: updated stale `isDevEnvironment()` docstring/comment to match fail-closed behavior, and changed `env.nodeEnv` default from `'development'` to `'unknown'` so the unset case is consistent (no consumers string-compare `env.nodeEnv`, verified repo-wide). Test-file truncation was a diff artifact only — file is complete and compiles. Committed as 03cbcf7 and pushed to staging. No PR to merge — Larry's flow ships directly to the `staging` branch; a staging→main promotion is a separate deploy decision.
luci-operator27d ago
Luci Operator: promoted this assigned `inbox` ticket to `todo` so pickup can run it.