Skip to content

Security: shivampkumar/mastermode

Security

SECURITY.md

Security posture

OpenClaw shipped 512 vulnerabilities in early 2026 and 21,000+ instances were exposed on the public internet leaking API keys. We watched that happen and took notes. MasterMode's design choices are largely a reaction to that incident.

What we don't do

  • No skill marketplace. OpenClaw's biggest blast-radius vector was user-installed third-party "skills" — over 800 of which turned out to be malicious. MasterMode has no plugin system and no remote-fetched code execution. All extension points (LLM provider, embedding provider, search provider) are pinned at install time via env vars.
  • No remote code loading. The chat agent's tools are a fixed list in lifeos/ai/tool_defs.py. The agent cannot install new tools, run shell commands, or write files outside the database directory.
  • No public-internet default binding. mastermode serve binds to 127.0.0.1 by default. To expose the API to other devices on a network, you have to explicitly pass --host 0.0.0.0. Even then we recommend Tailscale or a reverse proxy with auth — not direct exposure.
  • No global key store. Secrets live in the user's environment or in ~/.lifeos/mastermode.env (mode 0600 written by mastermode setup). Nothing writes API keys to the database, the audit log, or any user-facing payload.
  • No telemetry. No analytics, no crash reporting, no "anonymous usage statistics" beacons. The only network calls are to the LLM provider you configured, the embedding provider you configured, and any web search/fetch you explicitly asked the chat agent to do.

What we do

  • Audit log on every merge. lifeos/db/migrations/001_embeddings.sql creates an audit_log table. The dedup adjudicator writes a before/after payload there for every merge, with the actor (user / dedup_daemon / llm). Reversibility is by design: a tombstone of the loser is kept with canonical_id pointing at the winner.
  • Provenance on every fact. Each entity row carries a source column tracing the origin (user, llm, shivampkumar.com, voice:memo_2026-05-09.m4a, etc.). The chat path renders this inline so the LLM cites its source, and a user can audit the graph by source.
  • Pinning. mastermode pin <name> locks an entity. Pinned entities are never auto-merged or auto-edited. Use this for facts you've manually verified.
  • Local-first by default. The default embedding provider is BAAI/bge-small-en-v1.5 running locally via sentence-transformers. Combined with Ollama or a local LLM via LiteLLM, no embeddings or conversation text leave the user's machine.
  • Defensive deserialization. All LLM responses are parsed with bounded JSON extraction; malformed responses degrade to "no facts recovered" rather than executing anything.
  • Human-gate dedup. Cosine ≥ 0.97 → auto-merge with audit; cosine 0.88-0.97 → LLM adjudicator decides; user can flag a pair as permanently distinct via mastermode dedup distinct <a> <b>. The Java/JavaScript false-positive at 0.911 cosine demonstrates that naive auto-merge would corrupt the graph.

What we'd ask a security review to focus on

  1. Prompt injection through the web tools. web_fetch returns page content to the LLM. A malicious page could attempt to instruct the LLM to call other tools or leak data. Our guardrail is the Anthropic-style tool list (no shell, no fs writes outside DB), but we welcome a tighter audit.
  2. iOS Shortcut → /api/capture. The HTTP endpoint trusts whatever POSTs to it. If you expose serve over a network, anyone on it can add facts to your graph. We document Tailscale + auth-token patterns in the README; a hosted-mode deployment will need its own per-user auth model that we haven't built yet.
  3. Document chunking. Not yet implemented. When it lands, large PDFs and emails become attack surfaces; we'll harden the parser before that ships.

Reporting

Email shivampkumar [at] gmail [dot] com with details. We'll acknowledge within 72 hours and won't disclose specifics until a fix ships. No bounty program yet — but credit is offered.

Known gaps

  • No SBOM yet. We pin major versions in pyproject.toml; full reproducible builds via uv lock are on the roadmap.
  • No signed releases yet.
  • No content-security-policy on the React frontend's chat panel. Locally only it's low-risk; we'll fix before any hosted version.

There aren't any published security advisories