8fc88ffc14
Build & Push / Pipeline Tests (push) Failing after 59s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 51s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace 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
55 lines
2.5 KiB
Markdown
55 lines
2.5 KiB
Markdown
# Security design updates (Phases 0 & 3)
|
||
|
||
Summary of application-security design changes from the production-readiness program. Full finding table lives in `docs/ops/RentalDriveGo_Production_Readiness_Plan.md` §3.
|
||
|
||
## Closed in code (S1–S15)
|
||
|
||
| ID | Design rule now enforced |
|
||
|----|---------------------------|
|
||
| S1 | Team list/invite responses use safe presenters — never return password hashes or raw reset tokens |
|
||
| S2 | Per-tenant Docker/Compose orchestration is **out of production scope** (fail-closed + ADR-001) |
|
||
| S3 | Invite tokens hashed at rest (SHA-256) |
|
||
| S4 | Employee email unique per company; login fails closed on ambiguity |
|
||
| S5 | Post-login redirects limited to safe relative paths |
|
||
| S6 | Authenticated payment/subscription return URLs allowlisted |
|
||
| S7 | Admin company slugs validated / slugified |
|
||
| S8 | Admin presenters strip reset/verification secrets |
|
||
| S9 | Forwarded headers scrubbed by default; `TRUSTED_FORWARD_HEADERS=true` only behind a scrubbing edge (`docs/ops/proxy-trust.md`) |
|
||
| S10 | Password reset token lookup is hash-only |
|
||
| S11 | `reviewToken` is never returned in reservation/review API JSON (still used server-side for email links) |
|
||
| S12 | Public booking access: **read** does not burn the token; **payment init** atomically consumes an unused token |
|
||
| S13 | Admin money / privileged mutations require 2FA proof newer than `ADMIN_FRESH_2FA_MAX_AGE_MS` |
|
||
| S14 | `.gitignore` present for secrets/build artifacts |
|
||
| S15 | `npm run security:static` in CI |
|
||
|
||
## Public booking token (S12) flow
|
||
|
||
```
|
||
createBooking → mint publicAccessToken (hash stored)
|
||
│
|
||
├─ GET booking?token=… → validate (used or unused OK until expiry) — do not consume
|
||
│
|
||
└─ initPayment(token) → require usedAt IS NULL → updateMany set usedAt → proceed
|
||
(second payment attempt with same token → 404)
|
||
```
|
||
|
||
## Fresh admin 2FA (S13)
|
||
|
||
`requireFreshAdmin2FA` rejects when:
|
||
|
||
- TOTP not enrolled, or
|
||
- JWT lacks `last2faAt`, or
|
||
- `now - last2faAt > ADMIN_FRESH_2FA_MAX_AGE_MS` (default 30 minutes)
|
||
|
||
Wired on finance/support money and high-privilege admin mutations.
|
||
|
||
## Tenant isolation design
|
||
|
||
- App-level: every company resource query includes `companyId` from the authenticated session
|
||
- Regression suite: `apps/api/src/tests/integration/cross-tenant-isolation.test.ts`
|
||
- Postgres RLS: **deferred** (ADR-002) until the app-level suite and worker/migration roles are ready
|
||
|
||
## Pen-test
|
||
|
||
Scope pack: `docs/security/pen-test-scope.md`. Reports belong under `security-reports/` (evidence, not design).
|