client Frontend — React 18 + Vite SPA (TypeScript)
saas app shell · token-driven UI (light/dark) · TanStack Query · React Router. All MCP-origin strings rendered escaped (INV-8).
LandingLogin / RegisterDashboard + new-scan
Report + findings drill-downRaw JSON-RPC viewer
Endpoint history + grade trendCompare / diff
Share / exportPublic shared report
REST / JSON over HTTPS · httpOnly session cookie · double-submit CSRF▼
Backend — Hono on Node.js (TypeScript) · npm-workspaces monorepo (apps/api, apps/web, packages/shared)
http HTTP layer
Middleware chain (in order): security headers + CSP/HSTS → request-id + structured logging → rate limiter → session/auth → CSRF/Origin → router. Errors → RFC 9457 problem+json via onError on every router.
routes /api/*auth middlewareCSRF / Origin guard
rate limiter (ip · user)zod validationproblem+json errors
▼
services Service layer tenant-scoped via withUserScope (INV-5)
The only callers of the data layer. identity.ts is the pre-auth identity module (exempt from tenant scoping by design).
identity (auth · sessions · HIBP)ScanService
ReportServiceDiffServiceEndpointServiceShareService
▼
scanner core Deterministic engine no LLM in this path (INV-7)
A scan flows left → right. Hard caps: 10s deadline · 5 MB/response · JSON depth ≤ 64 · per-user concurrency ≤ 3.
SafeConnector
SSRF chokepoint: resolve-all-IPs deny-list, IP pinning, redirect re-validation
→
McpClient
JSON-RPC over Streamable HTTP: initialize → tools/resources/prompts·list (INV-14)
→
Normalizer
zod-validate untrusted items · canonical hash per definition
→
RuleEngine
7 detectors over a linear-time matcher (ReDoS-safe, INV-9)
→
Grader
severity → posture grade A–F
tool-poisoningexcessive-scopesecret-leak
rug-pullmissing-authtransport-hygiene
▼
data Data layer — Drizzle ORM
All user-scoped access via withUserScope. Secrets redacted before write; no table stores a user MCP auth token (INV-3).
▼
store PostgreSQL 16
9 tables · UNIQUE on lower(email) & (user_id, url_normalized) · per-tenant isolation.
userssessionsendpointsscans
findingsinventory_itemsscan_diffs
share_linksaudit_log
External systems & trust boundary
untrusted Target MCP server
Arbitrary user-supplied URL. Endpoint, DNS, responses, and any pasted token are all attacker-influenceable.
- Reached only through
SafeConnector(INV-1 / INV-2). - Denied: loopback · RFC1918 · link-local ·
169.254.169.254· ULA · IPv4-mapped-private. - Opt-in
SCAN_ALLOW_HOSTS(default empty) for trusted localhost dev servers.
outbound HaveIBeenPwned
Breached-password screening on register (NIST 800-63B).
- k-anonymity range API — only the first 5 SHA-1 hex chars leave the process.
- Fails open on outage; toggle with
HIBP_ENABLED.
Scan data flow
1 POST /api/scans → auth → rate limit → zod (scheme/userinfo/length).
2 ScanService find-or-creates the endpoint (ON CONFLICT) + a running scan row.
3 SafeConnector validates scheme, resolves & deny-lists every IP, pins the connection.
4 McpClient handshakes then enumerates tools/resources/prompts under caps (SSE + JSON).
5 Normalizer zod-validates & canonicalizes → ServerInventory + per-tool hash.
6 RuleEngine runs each detector → severity-ranked Finding[] (evidence redacted).
7 Grader maps findings → grade A–F.
8 ReportService persists report + findings; DiffService diffs vs the prior scan.
9 The auth token is discarded — it never leaves request scope (INV-3).
Architectural spine — enforced invariants
SSRF Egress containment
INV-1all user-host egress via SafeConnector.INV-2connector is the single chokepoint.INV-14initializeprecedes enumeration.
secrets Token & data handling
INV-3tokens never persisted.INV-4logger redaction (no raw tokens).INV-9linear-time matcher (ReDoS-safe).
isolation Tenant & UI safety
INV-5reads viawithUserScope.INV-7no LLM in detection path.INV-8nodangerouslySetInnerHTML.
Stack & deployment
runtime Technology
React 18ViteHonoNode LTS
PostgreSQL 16Drizzle ORMzodundici (IP pinning)
scrypt (node:crypto)pinoVitestPlaywright
deploy Topology
docker compose: db + app (API serves the built SPA).- HTTPS-only: TLS at a reverse proxy, HTTP→HTTPS redirect, HSTS.
- Structured JSON logs ·
audit_logtrail · header-buffer sizing.