SECURITY

Security posture, in plain language.

BuildOnAI is built for organisations where data sovereignty is a regulatory requirement, not a preference — law offices, medical research, clinical labs, public-sector operators, finance. The security posture is shaped around that constraint: nothing leaves the host by default, structural defences are CI-enforced, and every repository ships its own threat model.

Why this matters for regulated industries

The regulatory frame matters because it inverts the security question. The default assumption in most modern AI tooling is "data leaves the host, the cloud holds it safely, audit logs are good enough." For organisations covered by GDPR Art. 32, HIPAA §164.312, attorney-client privilege, ISO 27001 with data-residency clauses, or national-cybersecurity frameworks, that assumption is inverted: data cannot leave the host, and the burden of proof is on the operator.

BuildOnAI's design starts from the inverted assumption:

  • Self-hosted by default. Every service runs on hardware the operator controls. No cloud calls, no telemetry, no vendor lock-in. The optional fallback to a hosted LLM is opt-in via API key — without it, the ecosystem stays fully offline.
  • Document Processor stays local. Tauri desktop app written in Rust + Svelte. PDF / DOCX / TXT parsing happens on the host filesystem. Embeddings are generated by Ollama on the host. ChromaDB stores them on local disk. 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 by construction. Every privileged endpoint writes a structured JSONL audit line. 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 Engine refuses 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, ask on filesystem writes outside the project, allow on read-only commands). Custom rules go in policy.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 Server + AUTH_MODE three-mode dial (offobserveenforce) turns every inter-agent HTTP call into a signed transaction. Replays are blocked by short-lived nonces; clock drift over ~60 s is rejected. Public keys are plain files; revocation is rm. The migration path is gradual — see Secure deployment.

3. Document Processor isolation

Document Processor runs 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 leaves Document Processor only if the operator configures an explicit pipeline, like the one in Document pipeline.

4. CI-enforced invariants

Every 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. Disabling CI invariants voids commercial-licence guarantees; this is written into the licence as a contractual clause, not just a gentleman's agreement.

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 under AUTH_MODE=enforce (request is rejected; ed25519 verification fails).
  • Replay attacks against signed endpoints (nonce cache + timestamp window).
  • A compromised agent host being decommissioned mid-incident (rm the public key on key-server; revocation is immediate).

Out of scope

  • A determined attacker with arbitrary network access to the host's listening ports under AUTH_MODE=off (the default for solo / trusted-LAN deployments). If your environment doesn't match those assumptions, switch to enforce.
  • Malicious code in a Cortex plugin dropped into plugins/. Plugins are trusted-by-design today; PEP 684 subinterpreter isolation is on the roadmap (Cortex v1.2). Until then, treat plugins/ like you'd treat any directory of 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: