Skip to the content.

Security

The Hub is designed so a reachable non-loopback surface would already be a product bug. This page is the operator view. Vulnerability reporting is in SECURITY.md.

Threat model (short)

We assume We do not assume
You control the machine that runs the Hub The Hub is a public multi-tenant server
Assistants are untrusted guests Models will faithfully respect grants
Plugins and imported mail are hostile input Curation or “looks safe” is enforcement
Vault files on disk may be copied Plaintext SQLite is acceptable by default

Policy is evaluated in pch-core, outside any model’s reasoning.

Loopback only

pch, pch-server, and hub-desktop refuse a non-loopback --host (exit code 2). The message is: The Hub is not a public server; it binds loopback only.

Do not put a reverse proxy in front of :8765 that listens on a LAN or public interface. That would make the Hub a public server.

Encryption at rest

pch doctor reports whether encryption is on. From-source pch-server may open a plain database when the driver is missing and plain=True is used in tests — do not treat that as the product default.

Tokens and pairing

Token Who has it How you revoke it
Owner token Local UI via /v1/bootstrap Re-setup is not a daily operation; treat the machine as trusted
Connection token One paired assistant Agents → revoke, or revoke the grant

Send Authorization: Bearer <token> or X-PCH-Token. Missing or revoked tokens fail closed.

Never commit .cursor/mcp.json, pairing token files, google_oauth.json, .env, or vault databases. make check-secrets enforces a deny-list on tracked paths.

Grants

Grants are shown in plain language before confirm, are revocable, and apply to subsequent MCP and HTTP calls from that connection. Classification ceilings keep sensitive objects (for example Gmail artifacts) out of a private grant.

The forbidden_context pytest marker is the automated isolation gate. New grant or assembly behavior must extend it.

Plugins

Plugins run as child processes. They talk to the Hub over stdio JSON-RPC and never receive the vault key. hub.http.fetch is mediated against declared hostnames only. Undeclared access is denied by the host, not by marketplace review.

v1 plugins are import-only: they may upsert artifacts/events through kernel capabilities; they must not send mail, create external calendar events, export the vault, or extend the Hub UI.

Treat plugin output as untrusted data (authority=source_imported). It must not expand grants or be interpreted as instructions.

Imported content is data

Email, calendar, RSS, and PCA imports are a prompt-injection surface. The constitution rule is: they MUST NOT expand grants, alter policy, trigger actions, or be read as orders to the Hub or to an agent.

Audit

Consequential reads, writes, proposals, approvals, grant changes, and export/import are recorded in an append-only, hash-chained ledger. GET /v1/events/verify checks the chain. The UI Audit page is the human view.

CORS and local UI

The FastAPI app allows all origins because it is loopback-only. That is convenient for the SPA; it is not a reason to bind 0.0.0.0.

Reporting a vulnerability

Use GitHub Private Vulnerability Reporting on this repository. Do not open a public issue with exploit details. Do not paste vault exports, tokens, or OAuth client files into issues or pull requests.

In scope: defects that leak context, weaken vault encryption, bind beyond loopback, or escalate grants; unsafe defaults in packaging, recipes, or docs that would cause someone to commit secrets.