# Security Hardening Leftover Application Report

Project: RentalDriveGo / Car Management System  
Input archive: `car_management_system_hardened_applied.zip`  
Output archive: `car_management_system_leftover_applied.zip`  
Date: 2026-06-09

## Executive Summary

This pass applied the remaining source-level hardening gaps that were still practical to implement directly in the repository after the first hardening pass. The focus was on eliminating browser-readable authentication assumptions, enforcing app-layer blocking for the `x-middleware-subrequest` bypass class, improving actor-aware rate limiting, adding an admin 2FA recovery-code workflow, and bringing documentation/static checks into line with the hardened authentication model.

This does not replace production operator work such as real secret rotation, live infrastructure verification, container scanning, applying migrations to a real database, or running the complete CI/test pipeline. Those items remain launch-gate evidence requirements.

## Applied Changes

### 1. Removed remaining browser-side employee token assumptions

Changed files:

- `apps/dashboard/src/lib/api.ts`
- `apps/dashboard/src/components/layout/TopBar.tsx`
- `apps/dashboard/src/components/layout/Sidebar.tsx`
- `apps/dashboard/src/app/(dashboard)/team/page.tsx`
- `apps/dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx`

What changed:

- Removed dashboard use of employee auth tokens from `localStorage`.
- Dashboard API calls now use `credentials: 'include'` and depend on HttpOnly cookies.
- Dashboard Socket.io connection now uses cookie credentials instead of script-provided auth tokens.
- Team page no longer decodes employee identity from a localStorage JWT. It resolves the current actor through `/auth/employee/me`.
- Admin 2FA sign-in form now accepts either a six-digit TOTP code or a recovery code value.

Security effect:

- Reduces script-readable authentication exposure.
- Aligns the dashboard with the intended HttpOnly session-cookie model.
- Prevents UI code from treating a readable JWT as the authority for employee identity.

### 2. Added Socket.io HttpOnly-cookie session support

Changed file:

- `apps/api/src/index.ts`

What changed:

- Added Socket.io session-token extraction from HttpOnly cookies.
- Preserved explicit token verification for trusted non-browser/server contexts, while browser clients can now authenticate through cookies.
- Reused centralized actor-token verification.

Security effect:

- Real-time dashboard connections no longer require JavaScript-readable employee tokens.
- Socket authentication now follows the same actor-token validation path used elsewhere.

### 3. Added app-layer `x-middleware-subrequest` blocking

Changed files:

- `apps/api/src/app.ts`
- `apps/dashboard/src/middleware.ts`
- `apps/storefront/src/middleware.ts`
- `apps/admin/src/middleware.ts`
- `apps/dashboard/src/middleware.test.ts`
- `apps/storefront/src/middleware.test.ts`

What changed:

- API now rejects requests containing `x-middleware-subrequest` before route handling.
- Dashboard, storefront, and admin Next middleware now reject the same header at the app layer.
- Added/updated middleware tests for the rejection path.

Security effect:

- Adds defense in depth beyond reverse-proxy filtering.
- Prevents the project from depending on a single infrastructure control for this bypass class.

### 4. Hardened admin/browser fetch behavior

Changed files include:

- `apps/admin/src/lib/api.ts`
- `apps/admin/src/app/dashboard/admin-users/page.tsx`
- `apps/admin/src/app/dashboard/renters/page.tsx`
- `apps/admin/src/app/dashboard/companies/[id]/page.tsx`
- `apps/admin/src/app/dashboard/containers/page.tsx`
- `apps/admin/src/app/dashboard/pricing/page.tsx`
- `apps/admin/src/app/forgot-password/page.tsx`
- `apps/admin/src/app/reset-password/page.tsx`

What changed:

- Admin API wrapper uses `credentials: 'include'`.
- Manual admin fetch calls now include credentials where they directly call the admin API.
- Removed dead placeholder `getToken()` helpers that returned empty strings and created meaningless `Authorization: Bearer ` headers.

Security effect:

- Admin browser requests now consistently rely on the HttpOnly admin session cookie.
- Removes misleading bearer-token scaffolding from the admin UI.

### 5. Improved actor-aware rate limiting

Changed files:

- `apps/api/src/middleware/rateLimiter.ts`
- `apps/api/src/app.ts`

What changed:

- API rate-limit keys now prefer a verified actor identity from session cookies or valid Bearer tokens.
- Actor-aware rate limiting falls back safely to existing request actor fields or anonymous IP keys.
- Admin authentication routes now receive the stricter authentication limiter before the broader admin limiter.

Security effect:

- Authenticated traffic is limited by actor identity instead of only coarse IP data.
- Login and admin-auth abuse get stricter protection.
- Multi-container correctness still depends on Redis availability/configuration in production, which must be verified during deployment.

### 6. Added admin 2FA recovery-code backend workflow

Changed files:

- `packages/database/prisma/schema.prisma`
- `packages/database/prisma/migrations/20260610001500_add_admin_recovery_codes/migration.sql`
- `apps/api/src/modules/admin/admin.repo.ts`
- `apps/api/src/modules/admin/admin.service.ts`
- `apps/api/src/modules/admin/admin.schemas.ts`
- `apps/api/src/modules/admin/admin.routes.ts`

What changed:

- Added `AdminRecoveryCode` model.
- Recovery codes are stored as bcrypt hashes, not plaintext.
- TOTP enrollment now issues one-time recovery codes.
- Recovery-code regeneration is protected by authenticated admin access and fresh 2FA.
- Login can consume a valid unused recovery code when TOTP is enabled.
- Recovery-code issuance and use are audited.

Security effect:

- Adds a recovery path for mandatory admin 2FA without storing backup codes in plaintext.
- Preserves one-time-use semantics.
- Adds auditability for recovery-code lifecycle events.

Limitation:

- The backend returns recovery codes after enrollment/regeneration. A production-ready admin UI still needs to display them once with clear save instructions and must not persist them client-side.

### 7. Strengthened static scanning for auth-token regressions

Changed file:

- `scripts/security-static-check.mjs`

What changed:

- Static scan now catches common regressions involving auth/session token names in `localStorage` and `document.cookie`.
- Scan specifically targets auth token/session names such as employee/admin/renter tokens and sessions.

Security effect:

- Makes it harder for future code changes to quietly reintroduce script-readable authentication tokens.

### 8. Updated documentation to match the hardened model

Changed files:

- `apps/dashboard/README.md`
- `memory/project_auth_architecture.md`
- `docs/project-design/COOKIE_POLICY.md`
- `apps/api/src/swagger/openapi.ts`

What changed:

- Replaced stale localStorage/JWT handoff claims with HttpOnly session-cookie wording.
- Clarified that browser clients use HttpOnly sessions and that Bearer tokens are only for documented trusted server/mobile contexts.
- Updated cookie policy references from legacy `employee_token` wording to `employee_session`.

Security effect:

- Reduces the odds that a future developer follows stale documentation and reintroduces the old pattern.

## Validation Performed

The following checks were run successfully in the available environment:

```bash
npm run security:static
node --check scripts/security-static-check.mjs
# JSON parse validation for package.json and package-lock.json files
# YAML parse validation for docker-compose.production.yml and .gitlab-ci.yml
bash -n docker/entrypoint.production.sh scripts/docker-prod-*.sh scripts/docker-registry-local-up.sh scripts/setup-clerk-keys.sh
# TypeScript/TSX syntax transpile check over 507 source files
npm audit --package-lock-only --omit=dev --audit-level=critical
```

Results:

- Security static check: passed.
- Static-check script syntax: passed.
- Package JSON validation: passed.
- YAML validation: passed.
- Shell syntax validation: passed.
- TypeScript/TSX syntax transpile validation: passed.
- Critical production dependency audit: passed.

Audit note:

- `npm audit --audit-level=critical` exited successfully.
- Moderate advisories remain for transitive `postcss` and `uuid` paths. The available automatic fixes require breaking/force dependency changes, so they were not applied blindly in this source pass.

## Not Fully Verified in This Environment

The following items require a real development/CI/deployment environment:

- `npm ci` from a clean checkout.
- Full workspace typecheck.
- Full unit, integration, security, and e2e test suites.
- Prisma client generation.
- Applying the new database migration to a real database.
- Database backup/restore verification.
- Docker image build and runtime validation.
- Container scanning with Trivy or equivalent.
- Live reverse-proxy validation for `x-middleware-subrequest` blocking.
- Redis-backed distributed rate-limit validation across multiple API containers.
- Provider webhook sandbox tests.
- Live admin 2FA recovery-code UX verification.

## Remaining Launch-Gate Work

These are still not things source edits can prove by themselves:

1. Rotate all real production secrets.
2. Confirm no real secrets exist in repository history or image layers.
3. Apply and verify the new `admin_recovery_codes` migration.
4. Run the full CI gate: lint, typecheck, unit tests, integration tests, security tests, build, dependency audit, secret scan, and container scan.
5. Confirm Redis and PostgreSQL are private in production.
6. Confirm DB management tools are not publicly reachable.
7. Confirm production containers run non-root with reduced capabilities and resource limits.
8. Confirm webhook signature/idempotency behavior against real provider sandbox payloads.
9. Confirm private files are inaccessible through static routes in the deployed environment.
10. Confirm the admin UI displays recovery codes once and instructs admins to save them securely.

## Changed Files

See `security_hardening_leftover_changed_files.txt` for the complete file list and `security_hardening_leftover.diff` for the unified diff.

## Final Assessment

This pass closes a meaningful set of leftover source-level gaps from the security-hardening plan. The project is closer to the intended model: API-enforced security, HttpOnly browser sessions, stronger admin 2FA recovery, app-layer bypass blocking, and less stale documentation.

However, this still should not be treated as production-ready until the remaining launch-gate evidence is collected from CI and the live deployment environment. Security that has not been tested in the actual runtime is mostly optimism with a lanyard.
