Security Posture
The controls that keep an Uploz deployment honest, grouped by domain — what is enforced today, what is still partial, and what is owed before the PROD posture can be signed off. Postgres is the enforcement boundary (R5): Row-Level Security and the write-path RPCs are the spine of this board, and the verification rows track the adversarial confirmation (including a pending third-party pen-test) still outstanding.
15
Controls tracked
6
Enforced
9
Outstanding
40%
Fully enforced
Database (RLS + RPC)
Row-Level Security on all tenant tables
CriticalEvery tenant-scoped table denies by default; policies scope rows to the caller’s org via the JWT claim. RLS is the enforcement boundary, not the app layer (R5).
Evidence: force_row_level_security on each table; policy regression suite asserts cross-tenant reads return zero rows.
Supabase Postgres · R5
Writes only through SECURITY DEFINER RPCs
CriticalNo direct table grants to clients. State transitions go through validated RPCs (e.g. fn_request_transition) that re-check the transition boundary server-side.
Evidence: Anon/auth roles hold no INSERT/UPDATE/DELETE grants; transition-boundary tests gate illegal moves.
apps/web, apps/worker · R5
Service-role key is server-only
CriticalThe service-role key bypasses RLS and is restricted to the worker / server runtime. It is never bundled into the browser.
Evidence: Key read only from server env; build check fails if a NEXT_PUBLIC_* alias leaks it to the client bundle.
apps/worker
Authentication
JWT verification on every authenticated request
CriticalGoTrue-issued JWTs are verified on the read path; expiry and signature are checked before any RLS claim is trusted.
Evidence: Signature + exp validated at the API gateway; expired tokens are rejected before reaching Postgres.
Supabase API / Auth
JWT signing-key rotation
HighSigning keys are rotated on a schedule with an overlap window so live sessions are not dropped.
Evidence: Rotation procedure documented and rehearsed in DEV; PROD rotation cadence not yet automated.
Next: Wire the rotation into the scheduled job and alert on key age > 90 days.
Supabase API / Auth
dev-admin IP allowlist
HighThe internal cockpit is reachable in PROD only from an allowlisted CIDR range, read-only against PROD data.
Evidence: ADMIN_ALLOWLIST_CIDR enforced at the edge; SSO in front of the cockpit is still pending.
Next: Put SSO in front of dev-admin so access is identity-bound, not just network-bound.
apps/dev-admin
Transport
TLS termination at the edge
HighAll public traffic is HTTPS; the edge terminates TLS and forwards over the private network.
Evidence: Edge enforces HTTPS redirect; no plaintext listener exposed in PROD.
Edge / CDN
Security response headers (HSTS, CSP)
MediumHSTS, a restrictive Content-Security-Policy, and frame-ancestors are set on the app responses.
Evidence: HSTS + frame-ancestors live; CSP currently report-only while inline-style sources are tightened.
Next: Promote CSP from report-only to enforce after the report queue is clean for a week.
apps/web
Abuse / rate-limiting
Edge rate-limiting on public endpoints
HighPer-IP request budgets on auth and write-adjacent endpoints to blunt credential-stuffing and floods.
Evidence: Coarse per-IP limits live at the edge; per-account and per-RPC budgets not yet tuned.
Next: Add per-account limits keyed on the JWT subject and alert on sustained 429 rates.
Edge / CDN
Write-path RPC throttling
MediumTransition RPCs are throttled so a compromised session cannot drive runaway state churn.
Evidence: Design noted; no per-caller RPC budget enforced yet.
Next: Add a token-bucket check inside the SECURITY DEFINER RPCs keyed on caller + request.
Supabase Postgres
Supply chain
Contract-validated inputs
HighAll inbound payloads are parsed against the shared @uploz/contracts schemas before any write is attempted.
Evidence: Zod schemas reject malformed input at the boundary; security-input tests cover injection-shaped strings.
packages/contracts
Dependency vulnerability audit
MediumLockfile is audited for known-vulnerable transitive dependencies on each build.
Evidence: Audit runs in CI and reports; build does not yet fail on high-severity advisories.
Next: Gate the build on high/critical advisories once the current backlog is triaged.
CI
Secret scanning on commits
MediumPre-merge scanning blocks accidental commit of keys, tokens, and connection strings.
Evidence: Not yet wired; relying on reviewer vigilance and the server-only-key build check.
Next: Enable push-protection secret scanning on the repository.
CI
Verification
Third-party penetration test
HighExternal assessment of the auth, RLS, and write-path boundaries before the PROD posture is signed off.
Evidence: Scope drafted (tenant isolation, JWT, RPC abuse); engagement not yet booked.
Next: Book the engagement and reserve a remediation window after the report lands.
Security
Adversarial cross-tenant verification
CriticalIndependent confirmation that RLS cannot be bypassed via crafted JWTs or RPC argument tampering.
Evidence: Internal regression suite passes; awaiting the external pen-test to corroborate.
Next: Fold the pen-test findings back into the policy regression suite as new cases.
Security · R5
State legend
How each control’s lifecycle state maps onto the traffic-light vocabulary.
Authored from the architecture / security notes (illustrative project-tracking state, permitted per R1), not the output of a live scanner. The service-role key and write-path grants live server-side only; this board is read-only and never holds a credential.