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.
| Connector | Access | What it reads |
|---|---|---|
| Elasticsearch | Read-only | Log indices → grouped error signatures (counts, time range, trace IDs) |
| Grafana | Read-only | Metrics via the datasource proxy (panels, anomalies) |
| MongoDB | Read-only, allowlisted collections | Counts, staleness, status distributions — not full documents |
| PostgreSQL | Read-only, allowlisted tables | Counts, staleness, status distributions — not full rows |
| Redis / BullMQ | Read-only | Queue depths, failed/delayed jobs, key counts — never key values |
| Sentry | Read-only token | Grouped exceptions with the top in-app stack frame |
| Axiom | Read-only token | Log events via read-only APL queries → error signatures (counts) and recent rows |
| Shopify Admin | Read-only Admin API | Order / inventory / fulfillment data via the Admin GraphQL queries you supply or declare in config → summarized evidence (titles redacted). |
| Git | Local read | Commits, 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
--aiflag 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.jsonholds only non-secret fields — endpoint URLs, allowlists.horus secrets migratestrips any legacy plaintext out ofconfig.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 fromconfig.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.