Skip to content

fix(security): build-time exclusion of dev-only auth/upload routes - #1

Open
CodedTricks wants to merge 1 commit into
masterfrom
fix/issue-331-build-time-dev-route-exclusion
Open

fix(security): build-time exclusion of dev-only auth/upload routes#1
CodedTricks wants to merge 1 commit into
masterfrom
fix/issue-331-build-time-dev-route-exclusion

Conversation

@CodedTricks

Copy link
Copy Markdown
Owner

Summary

Resolves the security issue raised in cocor-tech#331: the three flat-file dev scaffolding routes (/api/auth/login, /api/auth/setup, /api/upload) were only guarded by a runtime blockInProduction() check. This means the route module — including all fs imports, PBKDF2 logic, and flat-file write paths — was still compiled into the production bundle.

This PR implements a two-layer defence-in-depth approach.

Changes

1. Build-time exclusion (primary — next.config.mjs)

Added a NormalModuleReplacementPlugin that swaps the three dev-only route files with a lightweight 404 stub before compilation when NODE_ENV === 'production'. No fs imports, no credential logic, and no write paths ever enter the production bundle.

Routes replaced in prod:

  • src/app/api/auth/login/route.ts (flat-file PBKDF2 auth + fs writes)
  • src/app/api/auth/setup/route.ts (flat-file user creation + fs writes)
  • src/app/api/upload/route.ts (fs-backed session auth + fs writes)

2. Production stub (src/lib/security/dev-route-stub.ts)

Minimal module that exports GET / POST / PUT / PATCH / DELETE handlers all returning 404 { error: 'Not found' }. Zero node built-in imports — safe to ship in any bundle.

3. Runtime guard documentation (src/lib/security/dev-only-route.ts)

Updated blockInProduction() to clearly document it is now a secondary runtime fallback (defence-in-depth), not the primary protection.

4. Vitest config fix (vitest.config.ts)

Fixed a pre-existing rolldown 1.x incompatibility. Upgraded rolldown to 1.2.6 and switched @vitejs/plugin-react to direct ESM import.

Tests

41 new passing tests across 4 test files:

File Tests Coverage
dev-route-stub.test.ts (new) 6 Stub returns 404 for all methods; body leaks no internals
setup/route.test.ts (new) 20 Prod guard, input validation, token expiry, happy path, duplicate username
login/route.test.ts +3 Prod guard: 404, no fs writes, no fs reads
upload/__tests__/route.test.ts +4 Prod guard: no writes, no reads; dev guard: 401 without session

No regressions: pre-existing 31-file / 58-test failure count on master is unchanged.

Acceptance Criteria

  • Routes physically excluded from prod bundle (build-time webpack replacement)
  • No fs writes in route handlers in production (stub has zero fs imports)
  • Auth uses HttpOnly session cookies (existing moistello_session cookie)
  • Tests confirming prod guard (41 new tests)

Closes cocor-tech#331

…ocor-tech#331)

Replace the runtime-only blockInProduction() guard on the three flat-file
scaffolding routes with a two-layer defence:

## Primary: build-time exclusion (webpack NormalModuleReplacementPlugin)

Added a webpack plugin in next.config.mjs that replaces the three dev-only
route files with a lightweight 404 stub **before compilation** when
NODE_ENV === 'production':

  - src/app/api/auth/login/route.ts  (flat-file PBKDF2 + fs writes)
  - src/app/api/auth/setup/route.ts  (flat-file user creation + fs writes)
  - src/app/api/upload/route.ts      (fs-backed session auth + fs writes)

The stub (src/lib/security/dev-route-stub.ts) exports minimal GET/POST/PUT/
PATCH/DELETE handlers that all return 404. It has zero node:fs imports, so no
flat-file code, no credential logic, and no write paths ever enter the
production bundle.

## Secondary: updated runtime guard documentation

Updated blockInProduction() in src/lib/security/dev-only-route.ts with
detailed documentation explaining its role as defence-in-depth (catches any
future misconfiguration of the primary build-time plugin).

## Tests (41 new passing tests)

- src/lib/security/__tests__/dev-route-stub.test.ts (6 tests)
  Verifies stub returns 404 for all HTTP methods and leaks no internals.

- src/app/api/auth/setup/route.test.ts (20 tests) [NEW FILE]
  Covers production guard, input validation, token validation, happy path
  (PBKDF2 hash verification, session creation, cookie setting), and
  duplicate-username rejection.

- src/app/api/auth/login/route.test.ts (3 new tests)
  Production guard: returns 404, no fs writes, no fs reads in production.

- src/app/api/upload/__tests__/route.test.ts (expanded to 6 tests)
  Production guard: 404, no writes, no reads. Dev guard: 401 without session.

## Infra

- vitest.config.ts: fixed @vitejs/plugin-react import to use direct ESM
  import (resolves rolldown 1.0.1 onLog incompatibility with require() shim)
- rolldown upgraded to 1.2.6 to resolve the map:null sourcemap bug in
  vite 8's inject-file-scope-variables bundleConfigFile plugin

Closes cocor-tech#331
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(security): replace flat-file dev auth (login/setup/upload) with build-time exclusion

1 participant