Threat model
A security claim nobody can falsify is marketing, not engineering. This page is the falsifiable kind: every promise below maps to a named cargo test — or, where a claim genuinely isn’t assertable inside a test (a Docker network topology fact, say), to a documented manual: justification instead of a stretched mapping.
The source of truth is
docs/threat-claims.md
in the repository; scripts/check-claims.sh fails the build if a claimed
test doesn’t exist, or if the register is ever gutted to zero rows. Delete
a test and the build tells on you.
Claims
Section titled “Claims”| Claim | Verification |
|---|---|
| Telegram owner messages are verified against the configured owner ID before owner routing | configured_owner_text_message_is_verified |
| Identity is not authority: a spoofed owner ID without a verified source is denied | spoofed_owner_id_without_verified_source_is_denied |
| Connector authentication and account role grant no trust by themselves | gmail_connector_authenticated_alone_does_not_match_the_selected_thread_route |
| External communication and content are treated as data, never instruction | email_reply_drafter_template_wraps_untrusted_context_on_the_wire |
The shell receives no raw connector credentials — only KERNEL_ENDPOINT and TASK_TOKEN |
process_driver_clears_env_and_sets_only_two_vars |
| The shell cannot directly call arbitrary external APIs in normal operation | manual: network egress containment is a Docker network property (compose.yaml’s openspine-internal network is internal: true) |
| Private-context model calls are mediated by the model gateway, with untrusted context sent wrapped, never raw | generate_sends_untrusted_context_in_body |
| User-selected targets are proven with selection tokens bound to the requesting grant | email_read_selected_thread_rejects_foreign_grant |
| Selection tokens are single-use | email_read_selected_thread_rejects_second_use |
| Authority is composed by deterministic intersection — no candidate allow means the action is not granted | no_candidate_allow_means_action_is_not_granted |
| Explicit deny wins over any allow | explicit_deny_overrides_allow |
| Approval-required overrides a plain allow | approval_required_overrides_plain_allow |
Every effectful action is mediated by gate() before dispatch |
approval_required_action_stops_before_dispatch |
| Audit records reference encrypted artifact refs for private payloads, never plaintext | audit_metadata_records_action_grant_and_refs_not_plaintext |
| The shell cannot widen its own authority without explicit owner approval | widening_via_a_proposed_pack_requires_approval_first |
| LLMs may not resolve authority-affecting route conflicts | priority_tie_with_equal_specificity_is_ambiguous |
| Final email send is denied regardless of grant or approval state | global_policy_round_trips_and_denies_send |
| Kernel replies are channel-bound: always sent to the grant-bound owner chat, never an override | lyra_ui_preview_sends_telegram_reply_to_grant_bound_chat |
| System-operations actions (host filesystem, raw network egress) are high-impact and denied by default | host_filesystem_read_and_write_are_denied_for_owner_control_grant |
What the current phases do not claim to defend against
Section titled “What the current phases do not claim to defend against”Honesty about the edges is part of the model. Out of scope today:
- A malicious root user on the host.
- A compromised kernel process or a compromised host OS.
- A model provider retaining data despite its stated policy.
- A user manually copying private data elsewhere after the kernel has legitimately shown it to them.
- Physical device compromise.
- All side-channel leakage.
These claims and exclusions refer to the OpenSpine/Lyra runtime substrate as a whole, not only the Lyra personal-assistant product.