Skip to main content
Comis is a headless, multi-agent daemon that connects autonomous AI agents to chat channels (Discord, Telegram, Slack, WhatsApp, iMessage, Signal, IRC, LINE, Email). It runs on a single trusted host, is mTLS/token-gated, and binds to loopback (127.0.0.1:4766) by default.
The canonical, version-controlled threat model is THREAT_MODEL.md in the repository root — this page mirrors it. Vulnerability reporting and the disclosure SLA live in SECURITY.md.
The defining assumption is load-bearing: the LLM agent is treated as a potential adversary. A model can be steered by prompt injection embedded in any content it reads — an inbound message, a fetched web page, an email, a transcript, an MCP tool result. The architecture is built to contain what a steered agent can do, not merely to authenticate the humans talking to it.

Trust boundaries

Zone / principalTrustRationale
Operator + host OSTrustedHolds the master key, config, and SQLite DB.
Gateway / RPC / WS clientsAuthenticatedmTLS and/or scoped, constant-time bearer tokens. No human passwords — identity is cryptographic.
LLM agent + model providerSemi-trustedOutput and tool requests are constrained, classified, and filtered.
Tools / skillsConfinedKernel sandbox with broker-mediated egress; risk-classified.
External contentUntrustedWrapped as data before reaching a prompt; never placed in the system role.
Other agents in the fleetMutually isolatedPer-agent scoped secrets, config, workspace, and budgets.

What Comis defends against

ThreatPrimary control(s)
Prompt-injection to tool/shell abuseKernel sandbox, action classification (destructive requires confirmation), broker-only egress, output scanning
Secret exfiltrationNo-enumeration SecretManager, the credential broker (agent holds only a placeholder), Pino redaction, output guard, memory-write validation
Unauthorized gateway/RPC accessmTLS + scoped, timingSafeEqual tokens; loopback-by-default bind
SSRF from web toolsvalidateUrl() (blocks private/loopback/link-local + cloud-metadata ranges) plus kernel broker-only egress
SSRF via MCP server redirectsThe in-process MCP client validateUrl()-checks every cross-host redirect target before following it (same-host redirects stay on the operator-configured server); a malicious server cannot bounce the daemon to metadata/localhost/RFC-1918
Memory poisoningvalidateMemoryWrite() (block / downgrade-to-external / store) and trust-ranked recall
Malicious or vulnerable MCP serversOSV pre-spawn scan, sandboxed spawn, circuit breakers; default-deny MCP server endpoint; cross-host redirect SSRF guard (above)
Supply-chain tamperingExact-pinned deps, bundled private packages, sigstore provenance, pnpm audit, CodeQL
Path traversal / symlink escapesafePath() (raw path.join is ESLint-banned)

What Comis does not defend against

Stated plainly, in the spirit of an honest threat model.
  • A compromised host or malicious operator — the operator holds the master key, config, and DB.
  • Full kernel sandboxing on non-Linux hostsbwrap is Linux-only; macOS uses best-effort sandbox-exec; Docker-Desktop/Windows run the exec/terminal tools unsandboxed.
  • The exec tool on a host with no sandbox provider — it currently fails open.
  • A fully adversarial model provider beyond what injection-wrapping and the output guard catch.
  • Brokering OAuth / subscription-token CLIs — only header/query API-key and bearer injection is brokered today.
  • Resource exhaustion / DoS from the operator’s own agents — budgets are a cost aid, not a hard boundary.
  • Confidentiality of data the operator deliberately routes to third-party providers or chat platforms.
  • Physical access, side channels, and compromise of Node.js or the OS itself.

Agent action classification

Every agent-driven action is classified by ActionClassifier. Unknown actions default to destructive (fail-closed), and the registry is locked after bootstrap so a malicious plugin cannot downgrade a classification at runtime.
ClassDispositionExamples
readNo side effects — auto-approvedfile.read, web.fetch, memory.search, channels.list
mutateReversible side effects — logged, auto-approvedfile.write, message.send, memory.store, browser.navigate
destructiveIrreversible / high-risk — requires confirmationfile.delete, memory.clear, system.exec, tokens.revoke, agents.delete
Confirmation gating is covered in Approvals; classified actions are recorded per Audit Logging.

Defense in depth

LayerControls
Compile-time / CIeslint-plugin-security + custom rules (ban eval, raw path.join, direct process.env); architecture tests including a secret-residency walker; CodeQL; pnpm audit --prod
RuntimeKernel sandbox + broker-only egress; ActionClassifier (fail-closed, locked registry); no-enumeration SecretManager; validateUrl SSRF guard; output guard + canary tokens; validateMemoryWrite; Node --permission model
Supply chainExact pins, bundled private packages, sigstore provenance, MCP OSV scan
See Defense in Depth, Skill Sandboxing, Exec Sandbox, and the Credential Broker.

Known limitations

Severity is the impact if the precondition is met.
GapSeverityStatus / mitigation
Kernel sandbox is Linux-onlyHigh (non-Linux)Linux is the supported production target; treat tool execution as unconfined elsewhere
exec tool fails open when no sandbox provider is presentHigh (misconfigured host)Tracked; defense-in-depth (command firewall, secret scrubber, SecretManager) still applies
Credential broker does not broker OAuth / subscription CLIsMediumOnly header/query API-key + bearer injection today
DNS-rebinding TOCTOU window in validateUrlLow–MediumBroker-only egress eliminates it for sandboxed tools
File-size governance debtLowTracked via the shrink-only fileSizeAllowlist
Self-reported benchmark figures (memory accuracy, cache savings) are self-authored, small-N, and LLM-judged — directional, not independent guarantees.

Reporting a vulnerability

Do not open public issues for vulnerabilities. Use the private reporting channel and follow the coordinated-disclosure process documented in SECURITY.md.