Skip to content

Security Checklist ​

Security is non-negotiable and enforced from day one. This page consolidates the rules and the pre-deploy checklist.

On every new endpoint ​

  • Zod validation on all req.body and req.query.
  • authenticate on all protected routes; requireActiveUser on all writes.
  • Ownership check in the service layer — never trust an ID from the client.
  • Sanitize free-text fields with sanitize-html before persisting.

Critical rules ​

RuleWhy
Never expose phone numbers in list/browse APIsOnly in the ACCEPTED-deal notification
Never return passwordHashExplicitly exclude it in Prisma selects
Mask phones in logs (XXXXXX${phone.slice(-4)})PII in logs
Never log request bodies with phone/tokensPII / secret leakage
CORS: only FRONTEND_URL + ADMIN_URL (+ ecropto.com)Never *
JWT only from Authorization: BearerNever from query params
Verify upload magic bytes; reject SVG; never reuse the original filenameSVGs can carry JS; generate keys with nanoid
Raw SQL only via Prisma tagged templatesNever $queryRawUnsafe with string concat
Never dangerouslySetInnerHTMLSanitize before persisting instead
Owner-only financials off counterparty serializersCost/margin/supplier/P&L privacy

Owner-only vs public data ​

  • Owner-only (private, never on a counterparty payload): buy cost, production cost, cost basis, blended cost, realised P&L, inventory valuation, supplier details, source-deal backlink. Guard tests assert no leak in serializeBatchForLead, getProductBatchSummary, available-batches, and lead/board rows.
  • Public (statutory / to any buyer): sale price, GI status/region, quality metrics, photos, GST bracket (gstRate, hsnCode).

Auth hardening ​

  • Access tokens 15m; refresh tokens 30d, device-bound, single-use rotation with a 60s grace window.
  • Login limiters count failures only; a success clears the phone + device counters.
  • DEACTIVATED users are rejected at the authenticate middleware.
  • The admin panel gates ProtectedRoute on role ∈ {admin, sub-admin} and classifies refresh failures terminal-vs-transient so a 5xx never logs an admin out.

Observability & privacy ​

  • Sentry.setUser({ id }) — id only (DPDP-compliant), never phone or PII.
  • Sentry DSNs are per-environment and empty in dev/CI so events are dropped silently.

Pre-deploy checklist ​

text
[ ] npm audit --audit-level=high passes (fix high/critical first)
[ ] No secrets in git history
[ ] All new routes have Zod schemas
[ ] All new routes accessing user resources have ownership checks
[ ] No console.log with phone numbers or tokens
[ ] Env vars in Railway (not in code)
[ ] File upload tested with a non-image file (must reject with 400)
[ ] ENABLE_TEST_ENDPOINTS unset, TEST_ENDPOINT_SECRET unset, TEST_OTP_PHONES unset
[ ] Coverage thresholds met (80/80/70/80)
[ ] Health check green on staging: GET /api/v1/health

Test-endpoint locks ​

The QA fast-path (/api/v1/test/*) has two independent locks — ENABLE_TEST_ENDPOINTS and TEST_ENDPOINT_SECRET. TEST_OTP_PHONES is separately gated and, where it deletes fixtures, hard-refuses any number outside the whitelist. All three must be unset on real production; the API logs a loud warning at boot if any are set.

Internal technical documentation — Cropto