fix architecture and write new tests
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
# 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/marketplace/src/middleware.ts`
|
||||
- `apps/admin/src/middleware.ts`
|
||||
- `apps/dashboard/src/middleware.test.ts`
|
||||
- `apps/marketplace/src/middleware.test.ts`
|
||||
|
||||
What changed:
|
||||
|
||||
- API now rejects requests containing `x-middleware-subrequest` before 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.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.
|
||||
Reference in New Issue
Block a user