# Manual Attack Surface Inventory: Kordant `web/` Generated: 2026-05-28 Scope: Kordant web application (SolidStart + tRPC + Drizzle ORM + Stripe + WebSocket) --- ## Entry Points ### HTTP Routes | Route | Method | Auth | Description | Key File | |-------|--------|------|-------------|----------| | `/api/trpc/[trpc]` | POST | Mixed (public/protected/admin) | tRPC endpoint — all tRPC procedures flow here | `web/src/routes/api/trpc/[trpc].ts` | | `/api/stripe/webhook` | POST | None (Stripe signature) | Stripe webhook handler | `web/src/routes/api/stripe/webhook.ts` | | `/api/stripe/session-status` | GET | None (public) | Check Stripe checkout session status | `web/src/routes/api/stripe/session-status.ts` | | `/api/health` | GET | None | Health check | `web/src/routes/api/health.ts` | | `/api/ready` | GET | None | Readiness check | `web/src/routes/api/ready.ts` | | `/auth/callback` | GET | None | Clerk OAuth callback | `web/src/routes/auth/callback.tsx` | | `/billing/checkout` | GET | None | Checkout page | `web/src/routes/billing/checkout.tsx` | | `/billing/return` | GET | None | Post-payment return page | `web/src/routes/billing/return.tsx` | ### tRPC Routers (16 total, key ones) | Router | Auth Type | Key Procedures | Key File | |--------|-----------|----------------|----------| | `extensionRouter` | Public | `getAuthStatus`, `linkDevice`, `reportPhishing` | `web/src/server/api/routers/extension.ts` | | `billingRouter` | Protected | `createCheckoutSession`, `createPortalSession`, `cancelSubscription` | `web/src/server/api/routers/billing.ts` | | `adminRouter` | Admin | `blogCreate`, `blogUpdate`, `userUpdateRole`, `stats` | `web/src/server/api/routers/admin.ts` | | `voiceprintRouter` | Protected | `createEnrollment`, `analyzeAudio` | `web/src/server/api/routers/voiceprint.ts` | | `darkwatchRouter` | Protected | `addWatchlistItem`, `runScan` | `web/src/server/api/routers/darkwatch.ts` | | `userRouter` | Protected | Profile management | `web/src/server/api/routers/user.ts` | | `reportsRouter` | Protected | Report generation | `web/src/server/api/routers/reports.ts` | | `spamshieldRouter` | Protected | Spam analysis | `web/src/server/api/routers/spamshield.ts` | ### WebSocket | Endpoint | Auth | Description | Key File | |----------|------|-------------|----------| | `ws://host:3001/?token=` | JWT in query param | Real-time alert broadcast | `web/src/server/websocket.ts` | --- ## Public Routes / URLs (No Auth Required) 1. `/api/trpc/extension.getAuthStatus` — Public tRPC query 2. `/api/trpc/extension.linkDevice` — Public tRPC mutation 3. `/api/trpc/extension.reportPhishing` — Public tRPC mutation 4. `/api/stripe/webhook` — Stripe webhook (signature-verified, no user auth) 5. `/api/stripe/session-status` — Stripe session status check 6. `/auth/callback` — Clerk OAuth callback 7. `/billing/checkout` — Stripe Checkout page 8. `/billing/return` — Post-payment return 9. `/api/health`, `/api/ready` — Health checks 10. Static pages: `/`, `/pricing`, `/features`, `/blog`, `/privacy`, `/terms`, `/about`, `/ads` --- ## Attacker Sources | Source | Capability | Access Level | |--------|-----------|-------------| | External attacker (internet) | Send HTTP requests, craft tRPC payloads, spoof Stripe webhooks, connect to WebSocket | Unauthenticated | | Compromised browser extension | Make tRPC calls with stored API key | Authenticated (as extension-linked user) | | Insider (non-admin user) | Access to own data via tRPC, WebSocket | Authenticated (user role) | | Insider (admin) | Full admin panel, blog management, user role changes | Authenticated (admin role) | --- ## Sinks | Sink | File | Description | Risk | |------|------|-------------|------| | Drizzle ORM queries | Multiple routers | SQL execution via `db.select`, `db.insert`, `db.update`, `db.delete` | SQL injection if user input reaches query builders | | Stripe API calls | `billing.service.ts`, `stripe.ts` | Payment operations, subscription management | Payment manipulation, webhook replay | | File system (audio) | `voiceprint/storage.ts` | `writeFile` for audio storage | Path traversal, disk exhaustion | | File system (reports) | `reports/generator.ts` | `writeFileSync` for PDF output | Path traversal | | Puppeteer | `reports/generator.ts` | `page.setContent(html)` — renders HTML to PDF | SSRF, XSS via crafted HTML | | External API calls | `darkwatch/scan.engine.ts` | `fetch()` to HIBP, SecurityTrails, Censys, Shodan | SSRF if user-controlled URLs reach fetch | | WebSocket messages | `websocket.ts` | `ws.send()` for alert broadcast | Alert flooding | | Database writes (webhook) | `billing.service.ts` | `db.insert(subscriptions)` on webhook events | Duplicate subscription creation | --- ## Hidden Control Channels | Channel | File | Description | Risk | |---------|------|-------------|------| | `process.env.APP_URL` | `middleware.ts` | Trusted as CORS origin | CORS origin injection if env is mutable | | `process.env.STRIPE_WEBHOOK_SECRET` | `webhook.ts` | Stripe signature verification key | Webhook replay if key is leaked | | JWT in `?token=` query param | `websocket.ts` | WebSocket auth token visible in logs | Token leakage via proxy/access logs | | Rate limiter path heuristic | `utils.ts` | `path.includes(p)` for sensitive paths | Rate limit bypass via path manipulation | | `scanStates` Map (in-memory) | `darkwatch.service.ts` | Scan state stored in process memory | State loss on restart, no persistence | | `userSockets` Map (in-memory) | `websocket.ts` | Socket connections stored in process memory | Memory exhaustion, no connection limit per user | --- ## Middleware / Proxy Assumptions | Layer | File | Assumption | Break Impact | |-------|------|-----------|-------------| | Security headers | `middleware.ts` | Sets CSP, HSTS, X-Frame-Options, etc. | Missing headers weaken defense-in-depth | | CORS | `middleware.ts` | Validates origin against whitelist | CORS misconfiguration if APP_URL is attacker-controlled | | Clerk auth | `middleware.ts` | Sets `ctx.user` from Clerk session | Auth bypass if Clerk session validation fails | | tRPC procedure types | `utils.ts` | `publicProcedure`, `protectedProcedure`, `adminProcedure` enforce auth | Privilege escalation if middleware is bypassed | | Rate limiting | `utils.ts` | Redis sorted set, tier-based limits | DoS if rate limit is bypassed | | Valibot schemas | `schemas/*.ts` | Input validation before service layer | Injection if schema is missing or weak | --- ## Key Files ### Authentication & Authorization - `web/src/middleware.ts` — Clerk middleware, security headers, CORS - `web/src/server/api/utils.ts` — tRPC procedure types, rate limiting middleware - `web/src/server/auth/jwt.ts` — JWT verification - `web/src/server/auth/session.ts` — Session management ### Stripe / Billing - `web/src/routes/api/stripe/webhook.ts` — Stripe webhook entry point - `web/src/server/services/billing.service.ts` — Billing service (webhook handler, checkout, subscriptions) - `web/src/server/stripe.ts` — Stripe client initialization - `web/src/server/api/schemas/billing.ts` — Billing input schemas ### tRPC Routers - `web/src/server/api/routers/admin.ts` — Admin procedures (blog, users) - `web/src/server/api/routers/billing.ts` — Billing procedures - `web/src/server/api/routers/extension.ts` — Extension procedures (PUBLIC) - `web/src/server/api/routers/voiceprint.ts` — Voice print procedures - `web/src/server/api/routers/darkwatch.ts` — DarkWatch procedures ### Services - `web/src/server/services/voiceprint.service.ts` — Voice analysis pipeline - `web/src/server/services/voiceprint/storage.ts` — Audio file storage - `web/src/server/services/darkwatch.service.ts` — DarkWatch scan orchestration - `web/src/server/services/darkwatch/scan.engine.ts` — External API scanning - `web/src/server/services/reports/generator.ts` — Report generation (Puppeteer) ### Real-Time - `web/src/server/websocket.ts` — WebSocket server (port 3001) ### Database - `web/src/server/db/index.ts` — Drizzle ORM database connection - `web/src/server/db/schema/*.ts` — Database schema definitions ### Rate Limiting - `web/src/server/lib/ratelimit.ts` — Redis-based rate limiter