-
Notifications
You must be signed in to change notification settings - Fork 0
Security
graft is local-first; the default surface is the AF_UNIX socket only. Enabling HTTP, remote bind, or encryption-at-rest is opt-in. This page documents the threat model and what's implemented.
Implicit trust boundaries:
- The user account that owns
~/.graft/is trusted. - The local AF_UNIX socket is reachable only by processes with
0600access (forced). - The HTTP layer, when enabled, is the only network surface.
Out of scope:
- Multi-user shared host without per-user profiles. Use per-user
GRAFT_HOME. - Untrusted code running as the graft user. Treat your DB as you treat any other personal SQLite file.
- Path forced
0600at creation. - The socket file is
unlinked at daemon shutdown. - No auth on the socket — anyone with FS access to it is trusted.
- File mode forced
0600on POSIX. - WAL mode; the
-wal/-shmfiles inherit the same mode.
Build the daemon against SQLCipher (not the default), then:
export GRAFT_DB_KEY="<passphrase>"
graft statsThe daemon applies PRAGMA key + PRAGMA cipher_compatibility = 4 at every open. Without the SQLCipher build, the env var is a no-op (logged at startup so you notice).
bind = 127.0.0.1. The daemon refuses to start with a non-loopback bind unless:
-
http.allow_remote: trueAND - Either
http.auth_tokenis set ORhttp.tls_terminated_externally: true.
This makes "accidentally exposed to the internet" impossible without an explicit operator decision.
-
http.auth_token— Bearer token for full access. Compared in constant time. EnvGRAFT_HTTP_AUTH_TOKENoverrides the config field, useful for systemd units. -
http.readonly_token— Optional second token, GETs only. POST/DELETE return 403. -
GET /v1/healthz— always unauthenticated (container probes).
When auth_token is set and a write reaches /v1/insert or /v1/nodes/{id} DELETE, the daemon validates the Origin (or Referer) header against an allow-list. Browsers always send Origin; CLI clients (curl, fetch from Node, daemon-to-daemon) skip the check naturally.
Each endpoint has its own toggle. Useful patterns:
- Public viewer dashboard:
endpoint_insert: false,endpoint_delete: false,endpoint_view: true,readonly_token: <viewer-team-token>. - Headless ingest worker:
endpoint_view: false,endpoint_insert: true, fullauth_tokenonly.
- The daemon drops privileges only to the user account it runs as. No setuid.
- llama.cpp runs in-process. CPU-bound. No outbound network from the daemon (the BGE-M3 model download happens via the CLI on first install).
- The HTTP listener is Mongoose (vendored). No raw socket handling in our code.
-
HTTP Host-header validation — DNS-rebinding mitigation via Host validation is not currently enforced in code. If you're binding
0.0.0.0, put a real reverse proxy in front and rely on its Host filtering. -
Rate limiting — none in graft itself. Add it at the proxy if you expose
/v1/*. -
Audit log — there's a
~/.graft/usage.jsonlusage log; it isn't tamper-evident.
Email security issues to the maintainer privately (see GitHub profile). Don't open public issues for vulnerabilities.
Install it in one command, and integrate it through whatever surface fits (CLI, REST, MCP,hooks). No SaaS. No API key. One binary.
Get started · Install · Integrate · Source · Issues · Apache 2.0 · pre-1.0, alpha
Welcome
Concepts
Reference
Adjacent
Operations