Audit all /api/* routes for missing authMiddleware coverage #561

Open
opened 2026-04-11 01:29:06 -04:00 by pook · 1 comment
Owner

Search the codebase for all Express route definitions (app.get, app.post, router.get, router.post, etc.) on /api/* paths. For each route, check whether authMiddleware (or equivalent JWT validation) is applied. List all routes and their auth status in a markdown table. Flag any route that handles user-specific data but lacks auth protection — these are security vulnerabilities (OWASP A01:2021). Post the full audit table as an issue comment. Do NOT attempt to fix any gaps — this is a read-only audit. Follow the same pattern as contractpilot issue #466.


Generated by CEO Planner (priority: 2)

Search the codebase for all Express route definitions (app.get, app.post, router.get, router.post, etc.) on /api/* paths. For each route, check whether authMiddleware (or equivalent JWT validation) is applied. List all routes and their auth status in a markdown table. Flag any route that handles user-specific data but lacks auth protection — these are security vulnerabilities (OWASP A01:2021). Post the full audit table as an issue comment. Do NOT attempt to fix any gaps — this is a read-only audit. Follow the same pattern as contractpilot issue #466. --- *Generated by CEO Planner (priority: 2)*
Author
Owner

API Route Authentication Audit (OWASP A01:2021 — Broken Access Control)

Framework: Hono (Express-compatible routing)
Scope: All API routes in packages/api/src/routes/
Date: 2026-04-11
Auditor: agent-bot (automated)


Route Mounting (packages/api/src/index.ts)

Mount Path Router
/health healthRouter
/api/health healthRouter
/documents exportRouter + documentHistoryRouter
/questionnaire questionnaireRouter
/generate generateRouter + generateTosRouter + generateDpaRouter
/billing billingRouter
/regulations regulationsRouter
/agency agencyRouter
/consent consentRouter
/api/admin adminRouter

Global Middleware (applied to all routes)

  • Body limit (100KB)
  • Logger, Pretty JSON
  • Security headers
  • Disclaimer middleware
  • CORS (restricted to ALLOWED_ORIGINS)
  • CSRF double-submit cookie (excludes /billing/webhook)
  • Rate limiter on /generate/* (5 req/60s/IP)

Full Route Audit Table

# Method Full Path Auth? Auth Method User Data? Severity
1 GET /health No No None
2 GET /health/ready No No None
3 GET /api/health No No None
4 POST /questionnaire No Yes (business info) Low
5 GET /questionnaire/:businessId/:documentType No Yes (business data) HIGH
6 POST /generate/privacy-policy No Rate limit only Yes (generates doc) Medium
7 POST /generate/terms-of-service No Rate limit only Yes (generates doc) Medium
8 POST /generate/data-processing-agreement No Rate limit only Yes (generates doc) Medium
9 POST /billing/checkout No Yes (userId in body) CRITICAL
10 POST /billing/webhook No Stripe signature No (M2M) None
11 GET /billing/portal No Yes (userId query param) CRITICAL
12 GET /billing/usage No Yes (userId query param) CRITICAL
13 GET /regulations/updates No No None
14 POST /regulations/check No No (documentId ref) Low
15 GET /regulations/affected/:documentId No No (public ref data) Low
16 POST /consent/record No Yes (session/consent) Low
17 POST /consent/withdraw No Yes (session consent) Medium
18 GET /consent/:sessionId No Yes (consent records) Medium
19 GET /documents/:businessId/history No Yes (doc history) HIGH
20 GET /documents/:id No Yes (document content) HIGH
21 GET /documents/:id/export Partial Auth header required (stub) Yes (doc export) HIGH
22 GET /agency/clients Yes Bearer token Yes OK
23 POST /agency/clients Yes Bearer token Yes OK
24 GET /agency/clients/:id Yes Bearer token Yes OK
25 PATCH /agency/clients/:id Yes Bearer token Yes OK
26 DELETE /agency/clients/:id Yes Bearer token Yes OK
27 GET /agency/white-label Yes Bearer token Yes OK
28 PUT /agency/white-label Yes Bearer token Yes OK
29 GET /agency/analytics Yes Bearer token Yes OK
30 GET /api/admin/webhook-failures Yes requireAdmin() Bearer Yes OK
31 PATCH /api/admin/webhook-failures/:id/resolve Yes requireAdmin() Bearer Yes OK

Flagged Security Vulnerabilities (OWASP A01:2021)

CRITICAL — Billing routes accept arbitrary userId without auth

Route File Risk
POST /billing/checkout billing.ts:30 Any client can initiate checkout for ANY userId
GET /billing/portal billing.ts:135 Any client can access ANY user's Stripe billing portal
GET /billing/usage billing.ts:147 Any client can read ANY user's usage/subscription data

Impact: An attacker can enumerate userIds and access or manipulate other users' billing — subscription hijacking, portal access, and usage data exposure.

HIGH — Document/questionnaire routes expose user data without auth

Route File Risk
GET /questionnaire/:businessId/:documentType questionnaire.ts:109 Anyone with a businessId can retrieve questionnaire answers
GET /documents/:businessId/history document-history.ts:21 Anyone with a businessId can list all generated documents
GET /documents/:id document-history.ts:65 Anyone with a document ID can read full document content
GET /documents/:id/export export.ts:13 Auth header required but validation is a stub (no JWT decode)

Impact: Document contents (privacy policies, ToS, DPAs) contain business-sensitive information. UUIDs are guessable via enumeration or leakage.

Additional Notes

  • Auth stubs, not real JWT: Both requireAdmin() and getAgencyUserId() only check token length >= 10 chars. The agency router treats the raw token string as the userId (see agency.ts:60: "Stub: In production, decode JWT and extract sub claim"). These pass the audit structurally but are NOT production-safe.
  • Consent routes (/consent/*) are intentionally public for GDPR compliance (consent must be recordable without login), but GET /consent/:sessionId should validate that the requester owns the session.
  • Generate routes are rate-limited but unauthenticated — acceptable for a freemium model but worth monitoring for abuse.

Summary

  • Total routes: 31
  • Authenticated: 10 (agency + admin) — all use Bearer token stubs
  • Unauthenticated with user data: 9 — these are vulnerabilities
  • Unauthenticated, public/infra: 12 — acceptable

Recommendation: Add proper JWT-based authMiddleware to all billing, document, and questionnaire routes before any production deployment. The current Bearer token stubs in agency/admin routes also need real JWT validation.


This is a read-only audit. No code changes were made.

## API Route Authentication Audit (OWASP A01:2021 — Broken Access Control) **Framework:** Hono (Express-compatible routing) **Scope:** All API routes in `packages/api/src/routes/` **Date:** 2026-04-11 **Auditor:** agent-bot (automated) --- ### Route Mounting (`packages/api/src/index.ts`) | Mount Path | Router | |---|---| | `/health` | healthRouter | | `/api/health` | healthRouter | | `/documents` | exportRouter + documentHistoryRouter | | `/questionnaire` | questionnaireRouter | | `/generate` | generateRouter + generateTosRouter + generateDpaRouter | | `/billing` | billingRouter | | `/regulations` | regulationsRouter | | `/agency` | agencyRouter | | `/consent` | consentRouter | | `/api/admin` | adminRouter | ### Global Middleware (applied to all routes) - Body limit (100KB) - Logger, Pretty JSON - Security headers - Disclaimer middleware - CORS (restricted to `ALLOWED_ORIGINS`) - CSRF double-submit cookie (excludes `/billing/webhook`) - Rate limiter on `/generate/*` (5 req/60s/IP) --- ### Full Route Audit Table | # | Method | Full Path | Auth? | Auth Method | User Data? | Severity | |---|---|---|---|---|---|---| | 1 | GET | `/health` | No | — | No | None | | 2 | GET | `/health/ready` | No | — | No | None | | 3 | GET | `/api/health` | No | — | No | None | | 4 | POST | `/questionnaire` | No | — | Yes (business info) | Low | | 5 | GET | `/questionnaire/:businessId/:documentType` | No | — | Yes (business data) | **HIGH** | | 6 | POST | `/generate/privacy-policy` | No | Rate limit only | Yes (generates doc) | Medium | | 7 | POST | `/generate/terms-of-service` | No | Rate limit only | Yes (generates doc) | Medium | | 8 | POST | `/generate/data-processing-agreement` | No | Rate limit only | Yes (generates doc) | Medium | | 9 | POST | `/billing/checkout` | No | — | Yes (userId in body) | **CRITICAL** | | 10 | POST | `/billing/webhook` | No | Stripe signature | No (M2M) | None | | 11 | GET | `/billing/portal` | No | — | Yes (userId query param) | **CRITICAL** | | 12 | GET | `/billing/usage` | No | — | Yes (userId query param) | **CRITICAL** | | 13 | GET | `/regulations/updates` | No | — | No | None | | 14 | POST | `/regulations/check` | No | — | No (documentId ref) | Low | | 15 | GET | `/regulations/affected/:documentId` | No | — | No (public ref data) | Low | | 16 | POST | `/consent/record` | No | — | Yes (session/consent) | Low | | 17 | POST | `/consent/withdraw` | No | — | Yes (session consent) | Medium | | 18 | GET | `/consent/:sessionId` | No | — | Yes (consent records) | Medium | | 19 | GET | `/documents/:businessId/history` | No | — | Yes (doc history) | **HIGH** | | 20 | GET | `/documents/:id` | No | — | Yes (document content) | **HIGH** | | 21 | GET | `/documents/:id/export` | Partial | Auth header required (stub) | Yes (doc export) | **HIGH** | | 22 | GET | `/agency/clients` | Yes | Bearer token | Yes | OK | | 23 | POST | `/agency/clients` | Yes | Bearer token | Yes | OK | | 24 | GET | `/agency/clients/:id` | Yes | Bearer token | Yes | OK | | 25 | PATCH | `/agency/clients/:id` | Yes | Bearer token | Yes | OK | | 26 | DELETE | `/agency/clients/:id` | Yes | Bearer token | Yes | OK | | 27 | GET | `/agency/white-label` | Yes | Bearer token | Yes | OK | | 28 | PUT | `/agency/white-label` | Yes | Bearer token | Yes | OK | | 29 | GET | `/agency/analytics` | Yes | Bearer token | Yes | OK | | 30 | GET | `/api/admin/webhook-failures` | Yes | requireAdmin() Bearer | Yes | OK | | 31 | PATCH | `/api/admin/webhook-failures/:id/resolve` | Yes | requireAdmin() Bearer | Yes | OK | --- ### Flagged Security Vulnerabilities (OWASP A01:2021) #### CRITICAL — Billing routes accept arbitrary userId without auth | Route | File | Risk | |---|---|---| | `POST /billing/checkout` | `billing.ts:30` | Any client can initiate checkout for ANY userId | | `GET /billing/portal` | `billing.ts:135` | Any client can access ANY user's Stripe billing portal | | `GET /billing/usage` | `billing.ts:147` | Any client can read ANY user's usage/subscription data | **Impact:** An attacker can enumerate userIds and access or manipulate other users' billing — subscription hijacking, portal access, and usage data exposure. #### HIGH — Document/questionnaire routes expose user data without auth | Route | File | Risk | |---|---|---| | `GET /questionnaire/:businessId/:documentType` | `questionnaire.ts:109` | Anyone with a businessId can retrieve questionnaire answers | | `GET /documents/:businessId/history` | `document-history.ts:21` | Anyone with a businessId can list all generated documents | | `GET /documents/:id` | `document-history.ts:65` | Anyone with a document ID can read full document content | | `GET /documents/:id/export` | `export.ts:13` | Auth header required but validation is a stub (no JWT decode) | **Impact:** Document contents (privacy policies, ToS, DPAs) contain business-sensitive information. UUIDs are guessable via enumeration or leakage. #### Additional Notes - **Auth stubs, not real JWT:** Both `requireAdmin()` and `getAgencyUserId()` only check token length >= 10 chars. The agency router treats the raw token string as the userId (see `agency.ts:60`: "Stub: In production, decode JWT and extract sub claim"). These pass the audit structurally but are NOT production-safe. - **Consent routes** (`/consent/*`) are intentionally public for GDPR compliance (consent must be recordable without login), but `GET /consent/:sessionId` should validate that the requester owns the session. - **Generate routes** are rate-limited but unauthenticated — acceptable for a freemium model but worth monitoring for abuse. --- ### Summary - **Total routes:** 31 - **Authenticated:** 10 (agency + admin) — all use Bearer token stubs - **Unauthenticated with user data:** 9 — **these are vulnerabilities** - **Unauthenticated, public/infra:** 12 — acceptable **Recommendation:** Add proper JWT-based `authMiddleware` to all billing, document, and questionnaire routes before any production deployment. The current Bearer token stubs in agency/admin routes also need real JWT validation. --- *This is a read-only audit. No code changes were made.*
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pook/compliancebot#561
No description provided.