Learn about our security practices, supported versions, and how to report vulnerabilities.
| Version | Supported |
|---|---|
| 1.23.x | |
| 1.22.x | |
| 1.21.x | |
| < 1.21 | No |
Please do not open a public GitHub issue for security vulnerabilities.
Email security reports to: security@traqify.com or reach the maintainer via @oyedokunken.
Include:
You will receive an acknowledgement within 48 hours and a full response within 7 days.
15-minute lifetime, HS256 only; signed with JWT_SECRET; carry tokenVersion — incremented on logout and password change to invalidate all outstanding tokens immediately
30-day opaque token stored only as a SHA-256 hash; sent as an httpOnly cookie that scripts cannot read; rotated on every use, and reuse of an old token revokes the session
Server-side code exchange; tokens stored in OAuthSession (2 min TTL); browser only receives an opaque one-time code — tokens never appear in the URL
SHA-256 hashed before storage; expires after 10 minutes; invalidated after 5 failed attempts
bcrypt cost factor 12; changePassword requires current password and enforces full complexity rules (uppercase, lowercase, digit, special character)
Four roles with descending privilege: OWNER > MANAGER > AUDITOR > CASHIER
Explicit FRONTEND_URL allowlist; credentials: true for cookie support without wildcard origin
Product images: JPEG/PNG/WebP max 5 MB. Downloadable files: explicit MIME allowlist max 4 MB. Multer memoryStorage — no disk writes
Zod schemas on every request body; all auth routes have full password complexity rules (uppercase, lowercase, digit, special character)
Every create/update/delete/login/export event logged with actor, entity, IP, user agent, and timestamp; append-only
Server throws before accepting any traffic if JWT_SECRET, DATABASE_URL, PAYSTACK_SECRET_KEY, or FRONTEND_URL are absent
Transaction verified server-side via Paystack API before any order is created; verified amount must match server-calculated total
Downloadable product file URLs are validated with URL.hostname.endsWith('.supabase.co') before any server-side fetch
GET /api/cron/ping requires Authorization: Bearer <CRON_SECRET>; Vercel injects the header automatically; the endpoint is not publicly exploitable