Security Architecture, Threat Modeling & Row-Level Security
1. Executive Summary & Security Philosophy
Debelu manages student commerce, digital escrow, bank accounts, and personal identification data. The platform implements a Zero-Trust Defense-in-Depth Architecture:
- Never Trust the Client: All financial calculations, fee determinations, delivery state transitions, and identity assertions execute server-side or inside database stored procedures.
- Fail-Closed Security: Any configuration ambiguity, unrecognized campus alias, or stale revision triggers an immediate
403 Forbidden(42501) or409 Conflict(40001). - Storage-Engine Isolation: Data protection does not rely solely on application middleware. PostgreSQL Row-Level Security (RLS) policies enforce cryptographic and user-bound isolation at the database layer.
2. STRIDE Threat Model & Marketplace Defenses
The system architecture addresses threats mapped across the STRIDE methodology:
| STRIDE Threat Category | Marketplace Attack Vector | Architectural Mitigation | Codebase Implementation |
|---|---|---|---|
| Spoofing Identity | Attacker forges JWT or impersonates another campus vendor. | Cryptographically signed Supabase JWTs with auth.uid() binding; dynamic role degradation engine. | [auth.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/debelu-backend/src/middleware/auth.ts) |
| Tampering with Data | Buyer tampers with product price or modifies category commission. | Immutable fee_snapshot JSON frozen at checkout; client prices ignored; server queries DB. | [db-order-fee-snapshot-checks.mjs](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/scripts/db-order-fee-snapshot-checks.mjs) |
| Repudiation | Vendor claims delivery was made; buyer falsely claims non-receipt. | Secret 4-digit Delivery PIN displayed only on buyer screen; atomic PIN verification trigger. | [escrow-lifecycle.md](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/docs/architecture/escrow-lifecycle.md) |
| Information Disclosure | Campus operator inspects orders or customer data from another university. | Scoped tenant isolation via admin_roles.campus_scope text[]; cross-campus queries return 0 rows. | [CampusOrderService.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/debelu-backend/src/services/CampusOrderService.ts) |
| Denial of Service | Flooding checkout intents or exhausting LLM tokens. | Tiered IP and user rate limiters; 7-layer Nduzi optimization caching; BullMQ concurrency caps. | [rateLimiters.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/debelu-backend/src/middleware/rateLimiters.ts), [aiRateLimiter.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/debelu-backend/src/middleware/aiRateLimiter.ts) |
| Elevation of Privilege | Compromised staff account attempts unilateral fee or balance modification. | The 4-Eyes Principle (Maker-Checker); AAL2 MFA enforcement; table privilege revocations. | [PlatformConfigurationProposalService.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/debelu-backend/src/services/PlatformConfigurationProposalService.ts) |
3. Row-Level Security (RLS) Policy Matrix
PostgreSQL RLS ensures that even if an application SQL injection vulnerability occurs, data isolation remains impenetrable at the engine layer:
graph TD
subgraph Client Roles
ANON[anon role]
AUTH_USER[authenticated role: Buyer / Vendor]
SERVICE[service_role - Background Workers]
end
subgraph RLS Execution Gate
RLS{PostgreSQL RLS Evaluator}
end
subgraph Tables & Isolations
PROD[(public.products<br/>Public SELECT if status='active')]
ORD[(public.orders<br/>Isolated by user_id or vendor_id)]
WALLET[(public.user_private_info<br/>Isolated by id = auth.uid())]
AUDIT[(public.audit_logs<br/>Append-only; Direct mutation revoked)]
end
ANON --> RLS
AUTH_USER --> RLS
SERVICE -->|BYPASSRLS| ORD
RLS -->|USING status='active'| PROD
RLS -->|USING user_id = auth.uid()| ORD
RLS -->|USING id = auth.uid()| WALLET
RLS -->|DENIED to authenticated| AUDIT3.1 Policy Specifications
| Table | Operation | Target Role | Policy Definition | Security Rationale |
|---|---|---|---|---|
products | SELECT | anon, authenticated | status = 'active' | Unapproved, draft, or quarantined items remain invisible to public queries. |
orders | SELECT | authenticated | user_id = auth.uid() OR vendor_id = auth.uid() | Prevents IDOR (Insecure Direct Object Reference); buyers and sellers only see their own transactions. |
orders | UPDATE | authenticated | DENIED | Direct updates to order total, status, or campus are rejected. All mutations mandate Security Definer RPCs. |
user_private_info | SELECT | authenticated | id = auth.uid() | Users can only inspect their own wallet balance and private financial ledger. |
payout_requests | INSERT | authenticated | vendor_id = auth.uid() AND auth.jwt()->>'role' = 'vendor' | Only verified merchants can initiate withdrawal requests. |
audit_logs | INSERT/UPDATE/DELETE | ALL | REVOKED | Immutable append-only audit trail; mutations rejected at PostgreSQL engine level. |
4. API Perimeter Defenses
Backend services on Fly.io are fortified with defense-in-depth HTTP middlewares:
graph LR
REQ[Inbound HTTP Request] --> HELMET[Helmet Security Headers]
HELMET --> CORS[CORS Origin Whitelist]
CORS --> RATE[Tiered Rate Limiter]
RATE --> IDEMP[Idempotency Middleware]
IDEMP --> CIRCUIT[Circuit Breakers]
CIRCUIT --> VALIDATE[Zod Schema Validator]
VALIDATE --> HANDLER[Domain Route Handler]4.1 Security Headers (Helmet & CSP)
Content-Security-Policy: Strict script-src with dynamic cryptographic nonces ([vite.csp-nonce.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/apps/storefront/vite.csp-nonce.ts)). Prevents Cross-Site Scripting (XSS) and malicious third-party script injection (Magecart defense).Strict-Transport-Security:max-age=63072000; includeSubDomains; preload(enforces HSTS).X-Frame-Options:DENYacross API and admin;SAMEORIGINon storefront.X-Content-Type-Options:nosniff.
4.2 Idempotency Middleware (idempotency.ts)
Financial POST endpoints mandate an Idempotency-Key header:
- When a key is received, Redis acquires an exclusive distributed lock (
TTL: 120s). - If a duplicate request arrives while processing $\to$ Returns
409 Conflict("Operation in progress"). - When processing completes $\to$ Cached response status and body are saved in Redis (
TTL: 24h). - Subsequent identical requests return the cached response immediately without re-debiting funds or duplicating orders.
4.3 Circuit Breakers (circuitBreakers.ts)
Protects backend infrastructure from cascading failure when upstream services (Paystack, Gemini AI, Resend) degrade:
- Failure Threshold: Trips open after 5 consecutive failures or timeouts ($> 15\text{s}$).
- Half-Open Probe: Tests upstream recovery with canary traffic after a 60-second cooldown window.
- Fallbacks: Gracefully degrades UI features (e.g., switches campus orders to pickup payment, disables AI chat tools) while maintaining platform uptime.
5. Webhook Integrity & Replay Mitigation
Inbound webhooks (Paystack, WhatsApp Business API) undergo cryptographic verification before entering application memory:
- Timing-Safe HMAC Verification:
crypto.timingSafeEqualprevents timing attacks on SHA-512 signatures. - Replay Protection: The database maintains a unique constraint on
processed_webhook_events(event_id). If Paystack retries a webhook that has already committed, the database detects the collision and returnsHTTP 200without re-executing escrow locks or balance updates.
6. Secret Isolation & Environment Segmentation
Debelu enforces zero secret leakage across client and server boundaries:
- Client Bundles: Storefront and marketing codebases access ONLY environment variables prefixed with
VITE_orNEXT_PUBLIC_(e.g.,VITE_SUPABASE_ANON_KEY,VITE_PAYSTACK_PUBLIC_KEY). - Server-Only Secrets:
PAYSTACK_SECRET_KEY,SUPABASE_SERVICE_ROLE_KEY,SUPABASE_JWT_SECRET, andGEMINI_API_KEYare provisioned strictly as encrypted runtime machine secrets on Fly.io. - CI/CD Validation: Automated pre-commit hooks and GitHub Actions workflows run static analysis scans to detect and prevent accidental secret commits.