squadcue

Security model

Threat model: single trusted user on their own machine, server bound to loopback. SquadCue refuses to start on a non-loopback host — there is no authentication layer, by design, until one exists.

Guards in place

The approval inbox is NOT a security boundary

It is a supervision workflow for agents you already trust to run on your machine. Understand what it does not stop:

  1. Approving a shell command approves the whole program. An approved Bash call can start sub-processes (curl | sh, Python, another CLI) that never pass the hook again.
  2. The hook lives in Claude Code’s settings. Claude Code can be configured to disable hooks (disableAllHooks, managed policies); a run whose settings drop the hook is simply unguarded. The hook itself fails closed (malformed input, unreachable server, internal errors, and timeouts all end in deny), but it can only decide calls that reach it.
  3. The API has no auth. Any local process can POST /api/approvals/{id}/decide and approve on your behalf; responded_via is client-supplied. Loopback binding is the only boundary.
  4. Several entry points bypass the gate by design, and are labeled as such in the UI: “Skip approvals” in employee chat, “Allow tools” on the New-task overlay, allow_tools on canvas claude nodes, and the Telegram ! prefix. All of these run --dangerously-skip-permissions.
  5. Silently allowed tools are local read/query only (Read, Grep, Glob, LS, TodoWrite, TodoRead, NotebookRead, BashOutput, ListMcpResourcesTool). WebFetch/WebSearch/Task require approval — but an approved Read still lets the agent load secrets into model context, which then rides along with any later approved network access. Approval controls actions, not information flow.

Data flows to be aware of

The Employees tab lists Claude Code sessions from claude_projects (default ~/.claude/projects) — the directory where the Claude Code CLI stores conversation logs. SquadCue scans this local directory: it globs session *.jsonl files, reads the first 80 lines of up to 40 recent files to extract each session’s working directory and opening message, and parses a session’s full history when you open its chat. Session-derived endpoints (discovery, chat history, chat send) return the first-launch disclosure / a 403 until consent is recorded in data/sessions_consent.json; decline and they stay off. The consent flag is a UX acknowledgment, not a security control — any process running as your user could write the flag file or read the transcripts directly. Point claude_projects elsewhere to scan a different (or empty) directory. SquadCue uploads none of it; content reaches your AI provider only when you chat.

Approval requests, run logs, and flow state live in plain JSON/JSONL/SQLite files inside the repo directory — greppable, deletable, yours.

Known limitations (accepted for the localhost single-user model)

Documented deliberately rather than hidden — pull requests welcome:

  1. No auth. Any local process can call the API. Loopback binding is the boundary.
  2. Prompt injection: content fetched from the web / files / issue text flows into agent prompts. When you enable “allow tools”, you are trusting that content. Keep allow-tools off for flows that ingest untrusted input.
  3. Child env: apart from ANTHROPIC_API_KEY, child processes inherit your environment (an allowlist is planned).
  4. readfile nodes can read any file your user can — treat flow definitions as trusted config.
  5. Frontend uses inline handlers with manual escaping; a CSP/refactor is planned.
  6. Flow-node agents are not covered by the global spawn semaphore yet — a runaway flow can spawn many CLI processes.
  7. Windows is the primary platform; session relaunch is Windows-only and the canvas shell node uses PowerShell.
  8. fetch SSRF guard has the resolve-twice TOCTOU window described above.
  9. The audit log records when/via/comment for each decision; in a single-user system “who” is you — there is no actor identity beyond that.

Report issues via GitHub Issues.