Local-first security boundaries
Local execution gives operators control over where their services and data run. It does not by itself establish legal or regulatory compliance; assess that against the requirements of each deployment.
The documented technical boundaries are:
- Self-hosted components. Services run on hardware the operator controls. Cortex's hosted fallback requires explicit configuration.
- Document Processor stays local. Tauri desktop app written in Rust + Svelte. PDF / DOCX / TXT parsing happens on the host filesystem. Search is SQLite FTS5 fused with embeddings from a local Ollama instance, and the index is a SQLite file on local disk. With Ollama unreachable, search degrades to lexical only rather than failing. The original document never crosses a network boundary.
- ed25519 inter-agent auth. When an organisation needs more than one agent or one host, every request is signed. Public keys live as plain files on the key-server; revocation is
rm. No external identity provider is required. - Audit trail on the signing boundary. The key-server writes a structured JSONL line for every verification it performs. Tail-and-alert is enough; no separate SIEM is required to start.
The four structural layers
"Structural security" means the protection is part of the architecture, not a process the operator has to follow. Four layers, each in a different repository, each with its own SECURITY.md:
1. Cortex Policy Engine
Cortex's Policy Enginerefuses dangerous tool calls regardless of who or what asked. A compromised prompt can ask the model to delete files; the policy refuses. Three rules ship by default (deny on destructive shell, askon filesystem writes outside the project, allowon read-only commands). Custom rules go inpolicy.json at the project root. The engine is the structural defence against prompt injection — no amount of clever input gets a human-confirmation step revoked once the policy says ask.
2. ed25519 signed requests
The Key Serverturns every inter-agent HTTP call into a signed transaction. Protected endpoints reject anything unsigned with a 401. Replays are blocked by short-lived nonces; clock drift over ~60 s is rejected. Public keys are plain files; revocation is rm.
3. Document Processor isolation
Document Processorruns as a Tauri desktop app — Rust core, Svelte UI, no embedded browser sandbox to escape. File system access is scoped to user-chosen directories via Tauri's allow-list; there is no remote endpoint for an attacker to reach. A parsed document remains in the application unless the operator exports it through a workflow they control.
4. CI-enforced invariants
Every product repository has a .github/workflows/pipeline with security invariants — Python AST checks for shell-injection patterns, capability-based fallback sentinels, known-public-endpoint whitelists, signed fixtures for migration tests. The invariants are part of the build, so a change that breaks one does not reachmain green.
What we protect against, what we don't
Each repository ships a SECURITY.md with the precise threat model for that component. Common shape:
In scope
- An untrusted prompt tricking the model into requesting a destructive action (Policy Engine refuses regardless).
- An unauthorised peer on the network calling protected endpoints (request is rejected; ed25519 verification fails).
- Replay attacks against signed endpoints (nonce cache + timestamp window).
- A compromised agent host being decommissioned mid-incident (
rmthe public key on key-server; revocation is immediate).
Out of scope
- A determined attacker with arbitrary network access to the host's listening ports. Signature verification protects the endpoints, not the ports themselves.
- Malicious code in a Cortex plugin dropped into
plugins/. Plugins are trusted code; treat the directory like any other executable code on the host. - Attacks on the host operating system itself. BuildOnAI is a userland service; it relies on the host's process isolation, container isolation, and filesystem permissions for the layers it doesn't own.
Vulnerability disclosure
If you've found a security issue, write to[email protected]with subject [SECURITY]. Initial acknowledgement within three business days. We'd rather fix something quietly and credit you in the release notes than learn about it on social media first.
Please do not file public GitHub issues for security reports. The SECURITY.md file in each repository describes the per-component reporting path and our response commitments.
Per-repository threat models
Every repository ships its own SECURITY.md with the authoritative threat model for that component:
- consciousness-server / SECURITY.md — signed-request boundary and deployment threat model.
- cortex / SECURITY.md — Policy Engine semantics and structural defence against prompt injection.
- document-processor / SECURITY.md — Tauri allow-list, no-network-by-default, classifier accuracy and false-positive notes.
- buildonai-key-server / SECURITY.md — IP allow-list, optional API-key header, audit log shape.