Files
Kordant/piolium/attack-surface/source-sink-flows-all-severities.md
2026-05-29 09:03:47 -04:00

95 lines
5.2 KiB
Markdown

# Source-Sink Flow Analysis Summary
**Generated**: 2026-05-28
**Phase**: L3 (SAST — Greppable Fallback)
**Target**: Kordant monorepo (web/, browser-ext/)
---
## Scan Overview
| Metric | Value |
|--------|-------|
| Files scanned | 730 |
| Candidate files | 218 |
| Candidate matches | 1412 |
| Draft findings produced | 12 |
| Keep (enriched) | 10 |
| Drop (enriched) | 2 |
## Candidate Classes Breakdown
| Class | Matches | High-Score Examples | Enriched | Kept | Dropped |
|-------|---------|---------------------|----------|------|---------|
| `raw-sql-query` | 611 | admin.ts, billing.ts, blog.ts (`.query()` calls) | N/A | 0 | 0 |
| `path-traversal-file-access` | 638 | blog/[slug].tsx, ext_bench.py, api.js (`.join()`) | 2 | 1 | 1 |
| `hidden-control-channel` | 42 | middleware.ts (CORS origin), trpc.ts (auth headers) | 4 | 3 | 1 |
| `command-execution` | 55 | test files, benchmarks (subprocess.Popen, exec.Command) | N/A | 0 | 0 |
| `dynamic-code-execution` | 12 | honker-bun/raw.exec(), test_sqlite_versions.py | N/A | 0 | 0 |
| `secret-literal` | 9 | billing.test.ts, auth routes (password error messages) | N/A | 0 | 0 |
| `unsafe-html-or-template` | 17 | blog/[slug].tsx (innerHTML), auth test files | 1 | 1 | 0 |
| `ssrf-capable-request` | 10 | billing/return.tsx (fetch), scan.engine.ts (external API) | 1 | 1 | 0 |
| `webhook-without-obvious-signature` | 6 | stripe/webhook.ts | 1 | 1 | 0 |
| `open-redirect` | 2 | blog/index.tsx, app.tsx | 1 | 1 | 0 |
| `weak-token-or-crypto` | 5 | PasswordInput.tsx (Math.random) | 1 | 0 | 1 |
| `public-entrypoint` | 5 | extensionRouter procedures | N/A | 0 | 0 |
## Key Filtering Decisions
### Dropped: `raw-sql-query` (611 matches)
- **Reason**: False positives — 99%+ are tRPC `.query()` method calls (not raw SQL), not Drizzle `sql<>` tag usage. The tRPC router `.query()` method is a framework method, not a SQL execution sink.
- **Exception**: The one real `sql<>` usage in admin.ts:47 was separately assessed as p4-012 (low severity, latent risk).
### Dropped: `command-execution` (55 matches)
- **Reason**: All matches are in test files (`test_*.py`, `*_test.go`, `*_spec.rb`) or benchmark scripts. These are development-time subprocess calls, not production attack surface.
### Dropped: `dynamic-code-execution` (12 matches)
- **Reason**: All matches are SQLite raw SQL execution methods (`raw.exec()`, `exec()`) in the honker package or test files. These are database operations, not code execution sinks.
### Dropped: `secret-literal` (9 matches)
- **Reason**: All matches are test data (`billing.test.ts`, `notification.service.test.ts`) or password validation error messages (`login.tsx`, `signup.tsx``"Password is required"` is not a secret).
### Dropped: `path-traversal-file-access` — 1 kept, 1 dropped
- **Kept (p4-005)**: `voiceprint/storage.ts``userId` not validated before `path.join()`, enabling arbitrary file write
- **Dropped**: `blog/[slug].tsx` — false positives from `.join("")` string concatenation (not filesystem path joins)
### Dropped: `weak-token-or-crypto` — 0 kept, 1 dropped
- **Dropped**: `PasswordInput.tsx``Math.random()` is used for generating HTML input element IDs, not for CSRF tokens or cryptographic purposes. The id is only used for `<label for=...>` association. Not a security issue.
## DFD/CFD Coverage
| DFD/CFD Slice | Covered by Findings | Notes |
|---------------|---------------------|-------|
| DFD-1: tRPC → Drizzle ORM | Partial (p4-012) | CVE-2026-39356 surface noted but no active injection found |
| DFD-2: VoicePrint Pipeline | Full (p4-005) | Path traversal in audio storage |
| DFD-3: Browser Ext → tRPC | Partial (p4-008) | superjson vulnerability in extension only |
| DFD-4: WebSocket Alerts | Full (p4-007, p4-011) | JWT leak + no Origin validation |
| DFD-5: Stripe Webhook | Full (p4-006) | Unsafe type coercion |
| CFD-1: Auth Flow | Partial (p4-011) | JWT in query param + no Origin check |
| CFD-2: Authz Flow | Full (p4-001) | Unvalidated role mutation |
| CFD-3: Rate Limiting | Full (p4-009) | Substring-based path matching |
## Custom Analysis Targets (Domain Attack Research)
| Target | File | Finding |
|--------|------|---------|
| CORS env var trust | `web/src/middleware.ts` | p4-003 |
| XSS via markdown rendering | `web/src/routes/blog/[slug].tsx` | p4-004 |
| Puppeteer SSRF | `web/src/server/services/reports/generator.ts` | p4-002 |
| Stripe webhook type safety | `web/src/server/services/billing.service.ts` | p4-006 |
| Return URL open redirect | `web/src/server/api/schemas/billing.ts` | p4-010 |
| superjson CVE | `browser-ext/package.json` | p4-008 |
| Rate limit bypass | `web/src/server/api/utils.ts` | p4-009 |
| WebSocket Origin check | `web/src/server/websocket.ts` | p4-011 |
| JWT in WS query param | `web/src/server/websocket.ts` | p4-007 |
| Admin role mutation | `web/src/server/api/routers/admin.ts` | p4-001, p4-012 |
| Audio path traversal | `web/src/server/services/voiceprint/storage.ts` | p4-005 |
## Agentic Actions Audit
Analyzed 2 GitHub Actions workflow files:
- `.github/workflows/ci.yml` — No AI agent actions found
- `.github/workflows/deploy.yml` — No AI agent actions found
**Result**: 0 findings. Standard CI/CD workflows with no Claude Code, Gemini CLI, OpenAI Codex, or GitHub AI Inference integrations.