Skip to content

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.

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.