11 KiB
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.tsapps/dashboard/src/components/layout/TopBar.tsxapps/dashboard/src/components/layout/Sidebar.tsxapps/dashboard/src/app/(dashboard)/team/page.tsxapps/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.tsapps/dashboard/src/middleware.tsapps/marketplace/src/middleware.tsapps/admin/src/middleware.tsapps/dashboard/src/middleware.test.tsapps/marketplace/src/middleware.test.ts
What changed:
- API now rejects requests containing
x-middleware-subrequestbefore route handling. - Dashboard, marketplace, 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.tsapps/admin/src/app/dashboard/admin-users/page.tsxapps/admin/src/app/dashboard/renters/page.tsxapps/admin/src/app/dashboard/companies/[id]/page.tsxapps/admin/src/app/dashboard/containers/page.tsxapps/admin/src/app/dashboard/pricing/page.tsxapps/admin/src/app/forgot-password/page.tsxapps/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 meaninglessAuthorization: Bearerheaders.
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.tsapps/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.prismapackages/database/prisma/migrations/20260610001500_add_admin_recovery_codes/migration.sqlapps/api/src/modules/admin/admin.repo.tsapps/api/src/modules/admin/admin.service.tsapps/api/src/modules/admin/admin.schemas.tsapps/api/src/modules/admin/admin.routes.ts
What changed:
- Added
AdminRecoveryCodemodel. - 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
localStorageanddocument.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.mdmemory/project_auth_architecture.mddocs/project-design/COOKIE_POLICY.mdapps/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_tokenwording toemployee_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:
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=criticalexited successfully.- Moderate advisories remain for transitive
postcssanduuidpaths. 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 cifrom 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-subrequestblocking. - 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:
- Rotate all real production secrets.
- Confirm no real secrets exist in repository history or image layers.
- Apply and verify the new
admin_recovery_codesmigration. - Run the full CI gate: lint, typecheck, unit tests, integration tests, security tests, build, dependency audit, secret scan, and container scan.
- Confirm Redis and PostgreSQL are private in production.
- Confirm DB management tools are not publicly reachable.
- Confirm production containers run non-root with reduced capabilities and resource limits.
- Confirm webhook signature/idempotency behavior against real provider sandbox payloads.
- Confirm private files are inaccessible through static routes in the deployed environment.
- 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.