# Balanced Chamber Summary — Kordant Security Audit **Phase**: L5 (Single Review Chamber + FP Check) **Date**: 2026-05-28 **Target**: Kordant monorepo (SolidStart + tRPC + Drizzle ORM + Stripe + WebSocket + Browser Extension) **Status**: CLOSED --- ## Executive Summary 19 draft findings were evaluated (12 from p4 SAST phase, 7 from l4 probe phase). After ideological challenge, false-positive elimination, and duplicate consolidation: - **Valid findings promoted to p8**: 11 - **Rejected (false positive)**: 1 - **Rejected (low severity)**: 3 - **Rejected (duplicate)**: 4 The 11 surviving findings cover XSS, SSRF, open redirect, rate limit bypass, CORS misconfiguration, webhook type safety, webhook replay, WebSocket authentication weaknesses, resource exhaustion, and vulnerable dependency usage. --- ## Finding Verdict Table | # | Source ID | Slug | Verdict | Severity | p8 Draft | |---|-----------|------|---------|----------|----------| | 1 | p4-004 | xss-in-innerhtml | VALID | HIGH | p8-001-xss-in-innerhtml.md | | 2 | p4-002 | puppeteer-ssrf | VALID | MEDIUM | p8-002-puppeteer-ssrf.md | | 3 | p4-010 | open-redirect-return-url | VALID | MEDIUM | p8-003-open-redirect-return-url.md | | 4 | p4-009 | rate-limit-substring-bypass | VALID | MEDIUM | p8-004-rate-limit-substring-bypass.md | | 5 | p4-003 | cors-origin-env-var | VALID | MEDIUM | p8-005-cors-origin-env-var.md | | 6 | p4-006 | webhook-type-coercion | VALID | MEDIUM | p8-006-webhook-type-coercion.md | | 7 | l4-001 | webhook-replay | VALID | MEDIUM | p8-007-webhook-replay.md | | 8 | p4-007 | websocket-jwt-query-param | VALID | MEDIUM | p8-008-websocket-jwt-query-param.md | | 9 | p4-011 | websocket-no-origin-validation | VALID | MEDIUM | p8-009-websocket-no-origin-validation.md | | 10 | l4-003 | voiceprint-resource-exhaustion | VALID | MEDIUM | p8-010-voiceprint-resource-exhaustion.md | | 11 | p4-008 | superjson-vulnerable-version | VALID | MEDIUM | p8-011-superjson-vulnerable-version.md | --- ## Rejected Findings ### False Positive (1) | Source ID | Slug | Reason | |-----------|------|--------| | p4-005 | path-traversal-audio-storage | `userId` comes from `ctx.user.id` (authenticated session), NOT user input — no path traversal vector exists | ### Low Severity (3) | Source ID | Slug | Reason | |-----------|------|--------| | p4-001 | unvalidated-role-mutation | No current privilege escalation path; role check only looks for `"admin"`; setting role to non-admin strings grants no privileges | | p4-012 | admin-sql-pattern | Latent risk only; current `sql<>` usage is safe (wraps `count()` aggregate); no active exploitation | | l4-007 | extension-noop-endpoints | Rate-limited at 5/min; no data corruption or privilege escalation; resource waste only | ### Duplicate (4) | Source ID | Slug | Duplicate Of | |-----------|------|-------------| | l4-002 | return-url-open-redirect-stripe | p4-010 (open-redirect-return-url) | | l4-004 | websocket-jwt-leakage-query-param | p4-007 (websocket-jwt-query-param) | | l4-005 | webhook-type-coercion-data-corruption | p4-006 (webhook-type-coercion) | | l4-006 | admin-role-unrestricted-value | p4-001 (unvalidated-role-mutation) | --- ## Severity Distribution | Severity | Count | Findings | |----------|-------|----------| | HIGH | 1 | XSS via unsanitized innerHTML | | MEDIUM | 10 | Puppeteer SSRF, Open redirect, Rate limit bypass, CORS origin, Webhook type coercion, Webhook replay, WebSocket JWT leak, WebSocket origin, VoicePrint exhaustion, Superjson CVE | | LOW | 0 | — | --- ## Threat Cluster Coverage | DFD/CFD Slice | Findings | Notes | |---------------|----------|-------| | DFD-1: tRPC → Drizzle ORM | 0 | CVE-2026-39356 surface noted; no active injection found | | DFD-2: VoicePrint Pipeline | 2 | p8-010 (resource exhaustion), p4-005 (FP) | | DFD-3: Browser Ext → tRPC | 1 | p8-011 (superjson CVE) | | DFD-4: WebSocket Alerts | 2 | p8-008 (JWT leak), p8-009 (no origin) | | DFD-5: Stripe Webhook | 2 | p8-006 (type coercion), p8-007 (replay) | | CFD-1: Auth Flow | 2 | p8-008 (JWT leak), p8-009 (no origin) | | CFD-2: Authz Flow | 0 | p4-001 rejected (low severity) | | CFD-3: Rate Limiting | 1 | p8-004 (bypass) | | DFD-6: Puppeteer Reports | 1 | p8-002 (SSRF) | | CFD-1 (CORS) | 1 | p8-005 (env var trust) | --- ## Attack Pattern Registry Updates ### New Patterns Identified | Pattern ID | Root Cause | Detection Signature | Severity | |------------|-----------|---------------------|----------| | AP-001 | Stored XSS via innerHTML + unsanitized markdown | Grep: `innerHTML=.*contentHtml` + `contentToHtml` with raw concatenation | HIGH | | AP-002 | Puppeteer SSRF via --no-sandbox + page.setContent() | Grep: `puppeteer.launch.*--no-sandbox` + `page.setContent` | MEDIUM | | AP-003 | Open redirect via unvalidated return URL | Grep: `return_url.*returnUrl` + `url()` validator only | MEDIUM | | AP-004 | Rate limit bypass via incomplete sensitive path list | Grep: `path.includes.*sensitivePaths` | MEDIUM | | AP-005 | CORS origin from unvalidated env var | Grep: `process.env.APP_URL.*allowedOrigins` | MEDIUM | | AP-006 | Webhook type coercion via chained `as unknown as` | Grep: `as unknown as Record` in billing | MEDIUM | | AP-007 | Webhook replay via missing event ID deduplication | Grep: `handleWebhookEvent` without `event.id` check | MEDIUM | | AP-008 | JWT in WebSocket query parameter | Grep: `searchParams.get.*token` in websocket handler | MEDIUM | | AP-009 | WebSocket no Origin validation | Grep: `verifyClient` missing in WebSocketServer config | MEDIUM | | AP-010 | Unbounded input → resource exhaustion | Grep: `minLength(1)` without `maxLength` in audio schemas | MEDIUM | | AP-011 | Vulnerable dependency version (superjson) | Grep: `superjson.*\^2.2.1` in package.json | MEDIUM | ### Variant Candidates (Not Promoted) | Candidate | Reason | |-----------|--------| | p4-005 (path traversal audio) | FALSE POSITIVE — userId from ctx.user.id | | p4-001 (unvalidated role) | LOW severity — no current exploit | | p4-012 (admin SQL pattern) | LOW severity — latent risk only | --- ## Key Observations 1. **No remotely triggerable CRITICAL findings** — All valid findings require some precondition (auth, admin access, log access, or env var injection). The highest severity is HIGH (stored XSS), which requires admin access for payload creation. 2. **WebSocket authentication is the weakest link** — Two findings (p8-008, p8-009) show that the WebSocket server lacks both Origin validation and uses JWT in query parameters. Together, these create a complete authentication bypass chain. 3. **Stripe webhook handler has two independent issues** — Type coercion (p8-006) and missing idempotency (p8-007) create a combined risk: a replayed forged webhook event can corrupt subscription data. 4. **Input validation gaps are systematic** — Multiple findings (p8-004, p8-009, p8-010) point to a pattern of missing maximum-length constraints and incomplete validation in valibot schemas. 5. **No active SQL injection found** — Despite the CVE-2026-39356 surface, no actively exploitable SQL injection was found in the current codebase. The `sql<>` tag usage in admin.ts is safe. --- ## Chamber Closure Findings written: 11 Patterns added to registry: 11 Variant candidates: 3 Chamber closed: 2026-05-28T13:00:00Z