Security

How Horus handles your code, credentials, and runtime data — local-first, read-only connectors, allowlists, and opt-in AI.

Horus touches sensitive systems — logs, source code, databases, queues, and error trackers. It is built local-first and read-only so investigations never put production at risk. This page describes exactly what Horus does, and does not do, with your data.

Security posture at a glance

  • Local-first: the CLI runs on your machine; Horus Cloud is optional; runtime connector queries execute from the CLI.
  • Read-only: every connector performs read-only, allowlisted operations. Horus never writes to your systems.
  • Local source analysis: the source-intelligence host analyzes code locally. Optional Cloud knowledge/report sync and AI features have separate data flows described below.
  • Evidence varies by connector: many sources return counts and signatures; logs and supplied Shopify queries can retain detailed content in report payloads.
  • Encrypted connector secrets: AES-256-GCM protects saved connector credentials. The master key comes from an environment variable, supported OS keychain, or a private fallback file.
  • Opt-in AI: investigations are deterministic by default; AI narration is an explicit flag.
  • Open source: the native CLI is auditable at github.com/Meritt-dev/horus-rust, and the source-intelligence backend at github.com/meritt-dev/horus.

Local-first by design

The Horus CLI runs entirely on your machine or CI runner. It reads from the systems you connect, builds evidence, and writes investigations to a local database. You can run Horus with no cloud account at all.

Connectors are read-only

Every runtime connector is a read-only adapter. Horus does not modify jobs, documents, rows, keys, dashboards, or issues.

ConnectorAccessWhat it reads
ElasticsearchRead-onlyLog indices → grouped error signatures (counts, time range, trace IDs)
GrafanaRead-onlyMetrics via the datasource proxy (panels, anomalies)
MongoDBRead-only, allowlisted collectionsCounts, staleness, status distributions — not full documents
PostgreSQLRead-only, allowlisted tablesCounts, staleness, status distributions — not full rows
Redis / BullMQRead-onlyQueue depths, failed/delayed jobs, key counts — never key values
SentryRead-only tokenGrouped exceptions with the top in-app stack frame
AxiomRead-only tokenLog events via read-only APL queries → error signatures (counts) and recent rows
Shopify AdminRead-only Admin APIThe data returned by supplied Admin GraphQL queries; titles are redacted, but result payloads can contain sensitive fields.
Azure Monitor / CloudWatch / Google Cloud LoggingLocal vendor CLI credentialsBounded log events, normalized messages and correlation fields
PrometheusRead-only query APIConfigured PromQL series and anomaly evidence
Azure Service BusManagement-plane readAllowlisted queue counts and status; no message receives
KafkaTopic/group read permissionsOffsets and lag; no consumption or commits
FirestoreRead access to allowlisted collectionsCounts and bounded date/status projections
SQL ServerSELECT-only loginCounts, newest dates, and top status groups from allowlisted tables
LensCloud workspace accessUser-filed reports, errors, failing requests, route, and release context
GitLocal readCommits, ownership, and change history from the local repository

Least privilege

Use dedicated read-only users and tokens per connector. Restrict MongoDB collections and PostgreSQL tables with explicit allowlists; omitting them enables discovery across the selected database/schema. Firestore, SQL Server, Service Bus, and Kafka require explicit resource lists. Enforce access boundaries with provider permissions.

What leaves your machine

By default, Horus sends only anonymous usage telemetry (Tier A) — command names, timings, success/failure, and where the engine ran out of evidence — with no file contents, queries, or secrets. Opt out with horus telemetry disable, HORUS_TELEMETRY=0, or DO_NOT_TRACK=1; CI collects nothing by default. Source analysis runs against your configured code-graph host and investigations are saved locally. Linking Cloud or enabling content telemetry introduces the additional data flows below.

  • Source analysis: local by default. An external --source host receives graph queries, plus the memory claims and investigation hints it embeds for recall; optional Cloud knowledge snapshots contain code-derived operations, types, and provenance.
  • Runtime evidence: fetched from connected systems. Report payloads may retain log messages, structured fields, and the results of supplied Shopify queries.
  • Horus Cloud (optional): linked investigations and their full saved report sync to your cloud project; agent runs, memory, and knowledge have their own sync paths — see below.
  • AI narration (optional): the --ai flag sends report context to Anthropic — see below.

Telemetry has two tiers. Tier A (anonymous usage metadata) is on by default. Tier B (redacted investigation input/output content) is off by default and requires explicit opt-in via horus telemetry enable-content. Tier B content is scrubbed before it leaves — secrets, cards, connection-string credentials, PEM keys, JWTs, AWS/GCP/Slack/GitHub tokens, emails, and IPs — and the payload is dropped entirely if a high-risk pattern survives. A first-run disclosure is printed once to stderr; opt-out precedence and CI-off behavior match the CLI.

Secrets and credentials

  • Connector secrets are AES-256-GCM encrypted at rest into .horus/secrets.local.json (gitignored, mode 0600) and are never stored in plaintext. config.json holds only non-secret fields — endpoint URLs, allowlists. horus secrets migrate strips any legacy plaintext out of config.json. Secret fields per connector: elasticsearch/grafana and Kafka username+password; mongodb/postgres/redis/SQL Server connection URL; Sentry auth-token; Axiom and Prometheus token; Shopify secret. Cloud log providers, Firestore, and Service Bus use locally managed vendor CLI sessions.
  • Prefer environment variables for secrets and reference them from config where supported.
  • Cloud CLI tokens are stored in ~/.horus/auth.json (home directory), never in the repo.
  • Redis credentials belong in the connection URL; Sentry uses a read-only auth token supplied via an environment variable.

Secrets are unlocked by a 32-byte master key held by your OS, not the repo. It is resolved in precedence order: HORUS_SECRET_KEY env var → OS keychain (macOS security, Linux secret-tool/libsecret, Windows DPAPI) → a 0600 key file at ~/.horus/keyring/master.key. It is auto-generated on the first secret write.

  • horus secrets status — show the key source, stored secrets, any plaintext in config, and gitignore state.
  • horus secrets migrate [--dry-run] — encrypt plaintext connector secrets and remove them from config.json.
  • horus secrets key [--show] — show the master key source; --show prints the base64 key for CI (HORUS_SECRET_KEY).

Horus Cloud

Horus Cloud is an optional shared layer for teams. Runtime connector queries and investigation execution run from your CLI or configured worker. Cloud stores uploaded results and also receives Lens reports and configured alert webhooks. Connected Cloud integrations can call their providers, such as Slack for report delivery.

  • Authentication uses a CLI token (horus login); only a hash of the token is stored server-side, and the plaintext is shown once.
  • Linking is explicit and per-repo (horus cloud link); unlink any time to return to local-only mode.
  • Synced data: investigations, evidence, agent runs, memory (authored claims and incident memory, as an allowlist of named fields plus links and audit), and explicitly pushed knowledge snapshots for the linked project. Memory syncs automatically and privately while the repo is linked and you are logged in; team sharing is a separate explicit promotion. Recall and hint vectors never sync.
  • Investigation sync uploads the complete saved report, including evidence payloads. Compact terminal/JSON output is a presentation format, not a Cloud privacy filter. Review the data your queries and logs return before linking a sensitive project.

AI features are opt-in

Investigations are deterministic by default — no model calls, reproducible output. The optional --ai flag enriches a report with narrative and uses your own Anthropic key, saved through horus connect ai or supplied as ANTHROPIC_API_KEY; when enabled, the hint, evidence titles and short excerpts, suspected causes, and hypotheses are sent to Anthropic. The published investigation command makes no AI narrative call without this flag. Local CLI provider preferences can be recorded with horus connect ai, but v0.24.3 narrative generation still uses the Anthropic API. Separately configured pilot workers run local Claude sessions; their provider account and tool policies apply.

Open source and self-auditable

The Horus CLI is open source. Review how connectors, recall, and sync behave in the native CLI at github.com/Meritt-dev/horus-rust, and the source-intelligence backend at github.com/meritt-dev/horus.

Reporting a vulnerability

Please report security issues privately via GitHub Security Advisories on the Horus repository rather than opening a public issue.