Daeseon Yoo
Back to project
·Troubleshoot·3 min

Codex full-repo audit before launch: 6 CRs from unauthed public routes to disabled CSP

Codex ran a whole-repo security and release-readiness audit and surfaced six concrete findings (CR-001 through CR-006), each tied to specific file:line evidence. One of them — the action-executor path-allowlist bypass — has already been fixed on main.

Before pushing toward a paid public launch, I had Codex run a full whole-repo audit of DalkkakAI (Tauri desktop + Hono server + Supabase web + local MCP gateway). It treated this as a weekly/monthly-grade verification pass: it read source, ran every test suite, ran the release gate, and explicitly excluded the separate claude_review/ tree so the two audits stay independent. What makes this trustworthy is the discipline — every finding cites concrete file:line evidence, targeted test suites and typechecks passed (302 desktop tests, 160 Rust lib tests, plus shared/action-sdk/server/web/mcp), and it clearly separates confirmed defects from unverified assumptions (live Fly/Vercel/Supabase state, payment flow, Apple notarization). Six findings landed, CR-001 through CR-006.

CR-001 — Public server exposes unauthenticated master-data routes (High). apps/server/src/app.ts:23 enables wildcard CORS via app.use("*", cors()), and the /home read (:28-35), /home/push write (:38-63), /widget/all + /widget KV read/write (:66-77), and ticket list/create (:81-94) all run with no auth — even though claim/release/status at :97-123 do gate on auth, and apps/server/fly.toml:10-19 deploys this as a public HTTPS service with REQUIRE_AUTH = "1". Impact: anyone who knows or guesses an identifier can read or tamper with home snapshots, widgets, and tickets. Fix: apply resolveUserId/Supabase JWT to every non-health route, scope by user/workspace, add a negative test that unauthenticated requests are rejected under REQUIRE_AUTH=1, and replace wildcard CORS with an explicit allowlist.

CR-002 — Desktop action executor bypasses the project path allowlist (High). apps/desktop/src-tauri/src/paths.rs:1-6 declares that project-path filesystem reach must go through PathAllowlist (gate at :44-53), but workitem_execute_action (lib.rs:1769-1814, registered at lib.rs:2220-2248) accepted a cwd: Option<String>, checked only that the directory exists, and ran allowed dev tools (cargo, pnpm, npm, go, python, node, git… from lib.rs:564-607) there — outside the intended boundary, persisting stdout/stderr to the graph. This one is already fixed on origin/main (commit 13a9105, 2026-06-19): the executor now confines cwd to the startup's granted PathAllowlist root with no process-cwd fallback.

CR-003 — Release-readiness gate is BLOCKED (High). pnpm release:readiness -- --dry-run ran but reported Release readiness gate: BLOCKED with 6 blockers: unchecked owner facts (docs/product/private-release-owner-checklist-2026-06-18.md:10-18), pricing/Merchant-of-Record conflicts, a missing checkout link, and a version split — landing/latest.json:2, apps/desktop/package.json:4, and tauri.conf.json:4 straddle 0.2.28 vs 0.2.34. The repo's own deterministic gate says paid/public release is not ready.

CR-004 — License key stored as plaintext app-data JSON (Medium). entitlement.rs:183-191 defines StoredLicense { license_key: String }, and :294-312 writes it as pretty JSON to dirs::data_dir()/DalkkakAI/license.json — directly contradicting the keychain-only secret contract in vault.rs:1-15. Fix: move the key to the OS keychain, keep only masked/non-secret metadata on disk, and migrate existing files.

CR-005 — Lint gate fails with 356 Biome errors (Medium). Root package.json defines "lint": "biome check .", but pnpm lint exits 1 with Found 356 errors. Found 1 warning. — mostly a11y (noAutofocus, useKeyWithClickEvents, useSemanticElements) plus noNonNullAssertion. The configured quality gate isn't actually passing, so regressions accumulate silently.

CR-006 — Tauri CSP disabled while rendering rich local content (Low). tauri.conf.json:23-24 sets "csp": null while LogPanel.tsx:553-557 renders transcripts via ReactMarkdown and MermaidCard.tsx:137-138 injects SVG via dangerouslySetInnerHTML. No confirmed XSS (ReactMarkdown doesn't enable raw HTML; Mermaid runs securityLevel: "strict") — flagged as defense-in-depth hardening, confidence Medium.

Net: one fix already landed (CR-002); CR-001, CR-003, and CR-004 are the must-fix-before-launch trio, with CR-005/CR-006 as cleanup.