Security and privacy
Threat model
Published as we use it internally. Each row names the threat, the boundary it crosses, the mitigation, and the phase in which the mitigation exists or is planned.
What we protect
- Imported engineering artifacts and everything derivable from them: addresses, device inventories, control sequences, alarm configuration, layouts.
- Secrets embedded in those artifacts: station passwords, tokens, certificates, service credentials.
- Live operational data: values, alarms, histories, which reveal occupancy and operations.
- The ability to write to a building.
- The integrity of the model itself.
- The software supply chain, because a release runs inside customer networks.
- Our own credentials: signing key, hosted secrets, pairing tokens.
Who we assume
- A malicious artifact author who hands a technician a crafted file.
- A network adversary on the customer LAN.
- A compromised hosted tenant or hosted insider, if a hosted service exists.
- A compromised hosted service trying to pivot into sites through the outbound channel.
- A supply-chain attacker: poisoned dependency, stolen key, tampered release.
- Over-privileged automation: an API or MCP client doing more than intended.
- A careless operator.
Boundaries
Controllers and devices to the edge (read-only by type). A vendor station to the edge (optional, outbound). Browser to the edge on the LAN (local authentication). Edge to hosted (optional, admin-enabled, outbound only). Tenant to tenant on hosted (isolation). The architecture page draws them.
Threats and mitigations
| # | Threat | Boundary | Mitigation | Phase |
|---|---|---|---|---|
| T1 | A crafted backup or controller file exhausts the machine (decompression bomb, oversized archive) | Import | Streaming unzip with hard caps on entry count, entry size, total inflated size and compression ratio; abort and report. | Phase 2 |
| T2 | XML external entities, DTDs or includes in a file | Import | Our own XML reader resolves nothing; fuzz corpus in CI. | Phase 2 |
| T3 | Deserialization of vendor objects | Import | Never used. Importers are pure XML and bytes; no vendor decoder runs on the edge. | By design |
| T4 | Path traversal from archive entry names | Import | Entries are read into memory by name and never written to disk. | Phase 2 |
| T5 | Secrets inside artifacts leak into the database, logs or the API | All | Typed redaction at import; artifacts encrypted at rest; no endpoint serves raw bytes; structured logs with a deny-list; no telemetry at all. | Phase 2–3 |
| T6 | Unauthenticated access to the edge on the LAN | Browser | Local accounts, first-run admin setup, session cookies, CSRF tokens, HTTPS with a local certificate and a documented path to a customer CA. | Phase 3 |
| T7 | A connector writes to a building | Connectors | Writing is a separate interface no early connector implements; BACnet/IP ships without the write service; a station connector has no write actions. | By design |
| T9 | A hosted service, or a compromised one, reaches into a site | Hosted | The edge initiates every connection; its message allowlist has no "open port" or "execute"; the hosted side can only answer requests. Short-lived enrollment codes; pinned certificate. | Phase 6 |
| T10 | One hosted tenant sees another | Hosted | Row-level security keyed on the session tenant; per-tenant artifact keys; integration tests that attempt cross-tenant reads. | Phase 6 |
| T11 | A malicious or vulnerable dependency | Supply chain | Lockfiles, vulnerability scanning and Dependabot in CI, minimal dependency count, SBOM per release, build provenance attestation. | Phase 0 |
| T12 | Theft of the signing key | Supply chain | Signing through a public transparency log from CI with short-lived identities; any hardware key for optional vendor modules never enters CI. CI verifies hash and signature against the tagged source. | Phase 3 |
| T13 | An MCP client or API consumer does more than the operator intended | API | Tools share the user's role; read-only by default; scoped queries; writes in a separate capability that is off; every call audited. | Phase 3 |
| T14 | A poisoned import rewrites a good model | Model | Imports produce a new snapshot; confirmed facts are never replaced; the diff of what an import would change is shown before it is accepted. | Phase 3 |
| T15 | An operator pastes customer data into an outside AI | People | No "ask AI" button that leaves the box; MCP is local-first; a data classification guide tells operators what an artifact contains. | Phase 3 (docs) |
Scope note: this covers Archipelago code and infrastructure. Vendor platforms are out of scope and governed by their own vendors' terms.