Audit performed: 2026-03-14. All findings from automated + manual review of the codebase.
- π΄ Open
- π‘ In Progress
- β Fixed
- βΈ Deferred
Status: β
Fixed
File: packages/backend/src/services/pdf.service.ts lines 25, 84
Issue: execAsync() called with shell string containing user-controlled file path. A crafted filename with shell metacharacters (;, &&, |) could execute arbitrary commands on the server.
Fix: Replace execAsync(commandString) with spawn() using argument arrays β no shell interpretation.
Breaking risk: Low β internal change only.
Status: β
Fixed
File: packages/backend/src/models/product.model.ts line ~83
Issue: excludeId interpolated directly into SQL string (AND id != ${excludeId}). Currently safe due to parseInt, but not parameterized β violates defense-in-depth.
Fix: Use $2 parameterized query.
Breaking risk: None.
Status: β
Fixed
File: packages/backend/src/controllers/users.controller.ts lines 50-54
Issue: Password reset only checks length >= 1. Trivially weak passwords accepted.
Fix: Enforce minimum 12 characters.
Breaking risk: Low β only affects new password creation.
Status: β
Fixed
File: packages/backend/src/index.ts, packages/backend/src/routes/auth.routes.ts
Issue: Only upload endpoint has rate limiting. Login endpoint open to brute-force. All API routes open to DoS.
Fix: Global rate limit on /api/* (100 req/15min); strict limit on /api/auth/login (10 req/15min).
Breaking risk: Low.
Status: β
Fixed
File: packages/backend/src/index.ts line ~27
Issue: origin: true allows any website to make credentialed requests to the API (CSRF vector).
Fix: Restrict to known frontend domains via CORS_ORIGIN env var.
Breaking risk: Low-Medium β must set env var correctly for production domain.
Status: β
Fixed (interim)
File: packages/backend/src/services/auth.service.ts line ~22
Issue: Stolen tokens valid for a full week. No refresh token mechanism.
Fix: Reduced to 24h. Full refresh token implementation deferred.
Breaking risk: Low β users log in again after 24h of inactivity.
Status: β
Fixed
File: packages/backend/src/services/auth.service.ts lines 14-18
Issue: Only checks JWT_SECRET exists, not that it's cryptographically strong.
Fix: Enforce minimum 32-character length at startup.
Breaking risk: Low β startup check only; existing strong secrets unaffected.
Status: β
Fixed
File: infrastructure/docker/nginx.conf
Issue: Only HTTP. Tokens and data transmitted in plaintext. No HSTS header.
Fix: Add SSL cert (Let's Encrypt), redirect HTTP β HTTPS, add HSTS header.
Breaking risk: Medium β requires cert setup; misconfiguration takes site down.
Status: β
Fixed
File: infrastructure/docker/nginx.conf
Issue: No CSP β XSS attacks can load external scripts freely.
Fix: Add CSP header allowing self + Google Fonts CDN + inline styles.
Breaking risk: Medium β Poppins font (Google CDN) needs explicit font-src allowance.
Status: β
Fixed
File: packages/frontend/src/context/AuthContext.tsx, packages/backend/src/controllers/auth.controller.ts
Issue: localStorage is readable by any JavaScript on the page. XSS attack can steal JWT.
Fix: JWT now stored in HttpOnly wiz3d_token cookie (SameSite=Strict, Secure in production). AuthContext restored via /api/auth/me on mount. api.ts uses withCredentials: true. Logout clears cookie server-side via POST /api/auth/logout.
Breaking risk: High β full auth flow refactor.
Status: β
Fixed
File: packages/backend/src/middleware/upload.middleware.ts lines 27-35
Issue: MIME type check uses file.mimetype which comes from the client and can be spoofed. A malicious file could be uploaded disguised as a PDF.
Fix: Validate actual file magic bytes (%PDF) after upload, reject and delete if invalid.
Breaking risk: Low β only affects malformed/malicious uploads.
Status: β
Fixed
File: packages/backend/src/middleware/error-handler.ts line ~58
Issue: err.message returned to client in non-production environments, leaking internal details.
Fix: Always return generic error message to client; log details server-side only.
Breaking risk: None.
Status: β
Fixed
Issue: All controllers pass req.body directly to services without schema validation. Allows over-posting, type confusion, excessively long strings.
Fix: Zod validation schemas added to all 8 controllers (auth, users, queue, upload, customer, product, sales-invoice, color). Invalid input returns 400 with field-level error messages.
Breaking risk: Low β rejects invalid input that currently passes through.
Status: β
Fixed
Issue: No CSRF tokens on state-changing endpoints. Mitigated partially by Bearer token auth but not fully if CORS is open.
Fix: CSRF token (48-char hex) embedded in JWT payload, returned in login/register/me response body. Frontend stores in React state only; sends as X-CSRF-Token header on all POST/PUT/PATCH/DELETE. requireAuth middleware validates token on mutating requests.
Breaking risk: Low-Medium.
Status: β
Fixed
Issue: No persistent log of sensitive actions (user creation, invoice changes, status updates). Console logs are ephemeral.
Fix: Added audit_logs table (migration 018); logs actor, action, resource, detail, timestamp on: user create/update/delete/reset-password, invoice create/delete/send/ship/send-to-queue.
Breaking risk: None β additive only.
Status: β Fixed Issue: Tokens valid 7 days with no activity-based expiry. Fix: 30min idle timer in AuthContext; 60-second countdown warning modal before auto-logout. Breaking risk: Low.
Status: β
Fixed
File: packages/backend/src/config/database.ts
Issue: No ssl option in pg pool config. If DB is remote, credentials/data sent in plaintext.
Fix: Enable ssl: { rejectUnauthorized: false } for production.
Breaking risk: Low β config-only change.
Status: β
Fixed
File: packages/backend/src/middleware/upload.middleware.ts
Issue: UPLOAD_DIR env var used without path traversal validation.
Fix: Resolve and validate path stays within expected root at startup.
Breaking risk: None.
Status: β Fixed Issue: Customer email stored without format validation. Malformed emails silently saved. Fix: Validate email format in customer create/update controller. Breaking risk: Low β rejects invalid emails on write.
Status: β
Fixed
File: packages/backend/src/routes/users.routes.ts
Issue: Admin password reset endpoint has no rate limiting.
Fix: Add rate limiter to password reset route (5 req/15min).
Breaking risk: None.
Status: β
Fixed
File: packages/backend/src/services/auth.service.ts
Issue: Failed login attempts not logged β brute-force attacks invisible.
Fix: Log failed attempts with timestamp and username (not password).
Breaking risk: None.
Status: β
Fixed
Fix: Added Referrer-Policy and Permissions-Policy to nginx (both server and static file location blocks).
Status: β
Fixed (audit)
Fix: Ran npm audit fix β patched multer (3 high DoS CVEs). Caret ranges remain; audit should be run regularly.
Status: β
Fixed
Fix: Validate OLLAMA_MODEL against an allowlist at startup; exits if not recognized.
-
C1 β Command injection -
C2 β suggestSku parameterization -
C3 β Password minimum length -
H1 β Rate limiting -
H4 β JWT secret strength check -
H8 β PDF magic byte validation -
H9 β Error handler message leak
-
H2 β CORS restriction -
H5 β HTTPS / HSTS -
H6 β Content-Security-Policy
-
H3 β JWT expiry (24h) -
H7 β JWT β HttpOnly cookies -
M1 β Input validation (Zod) -
M2 β CSRF protection -
M3 β Audit logging