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 and never connects to your runtime.
  • Read-only: every connector performs read-only, allowlisted operations. Horus never writes to your systems.
  • Source code stays local: source intelligence builds a code graph on a local host; your source is not uploaded.
  • Summarized evidence: connectors return counts, signatures, and statuses — not raw rows, documents, or key values.
  • Encrypted at rest: connector secrets are AES-256-GCM encrypted; the master key lives in your OS keychain, never the repo.
  • Opt-in AI: investigations are deterministic by default; AI narration is an explicit flag.
  • Open source: the CLI is auditable 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 APIOrder / inventory / fulfillment data via the Admin GraphQL queries you supply or declare in config → summarized evidence (titles redacted).
GitLocal readCommits, ownership, and change history from the local repository

Least privilege

Use dedicated read-only users and tokens per connector. MongoDB collections and PostgreSQL tables must be explicitly allowlisted.

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 intelligence runs against a local code-graph host, so your source code is never sent anywhere, and investigations and evidence are written to a local database.

  • Source code: never uploaded — analyzed by a local source-intelligence host.
  • Runtime evidence: fetched from your connected systems and summarized locally.
  • Horus Cloud (optional): if you link a repo, investigation results, evidence, agent runs, and knowledge snapshots sync to your cloud project — 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 username+password, mongodb/postgres/redis URL, sentry auth-token, axiom token, shopify secret.
  • 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] — print the base64 master key for CI (HORUS_SECRET_KEY).

Horus Cloud

Horus Cloud is an optional shared layer for teams. The CLI gathers evidence and runs agents locally; only the results sync to your cloud project. Cloud never connects to your runtime systems.

  • 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, and knowledge snapshots for the linked project.
  • Evidence stays summarized, not raw — the same minimization that applies locally applies to what syncs.

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 requires your own ANTHROPIC_API_KEY; when enabled, report context is sent to Anthropic. Without the flag, no investigation data is sent to any AI provider.

Open source and self-auditable

The Horus CLI is open source. You can review exactly how connectors, source intelligence, and sync behave 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.