8aab968e09
Build & Deploy / Build & Push Docker Image (push) Successful in 1m2s
Test / Type Check (all packages) (push) Failing after 28s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Storefront Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
Build & Deploy / Deploy to VPS (push) Successful in 3s
Comprehensive rename of all marketplace references to storefront: - API module: apps/api/src/modules/marketplace/ → storefront/ - Components: MarketplaceHeader → StorefrontHeader, MarketplaceShell → StorefrontShell, MarketplaceFooter → StorefrontFooter - Types: marketplace-homepage.ts → storefront-homepage.ts - Test files: employee-marketplace-* → employee-storefront-* - All source code identifiers, imports, route paths, and strings - Documentation (docs/), CI config (.gitlab-ci.yml), scripts - Dashboard, admin, storefront workspace references - Prisma field names preserved (isListedOnMarketplace, marketplaceRating, marketplaceFunnelEvent) as they map to database schema Validation: - API type-check: 0 errors - Storefront type-check: 0 errors - Dashboard type-check: 0 errors - Full monorepo type-check: only pre-existing admin TS18046
256 lines
11 KiB
Markdown
256 lines
11 KiB
Markdown
# 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.
|