Security model

honeycomb captures coding sessions and memories, which is some of the most sensitive data a developer tool handles. Its security model rests on one structural decision: the daemon is the only process that talks to storage, so the storage-facing attack surface is a single chokepoint where scoping,…

Security model

Derived from the honeycomb knowledge base, captured 2026-06. Written for an external practitioner. This page describes the design and the contracts; it does not include internal operational runbooks. Confirm any version-specific detail against your installed version.

#The concept

honeycomb captures coding sessions and memories, which is some of the most sensitive data a developer tool handles. Its security model rests on one structural decision: the daemon is the only process that talks to storage, so the storage-facing attack surface is a single chokepoint where scoping, escaping, encryption, and isolation all live. Everything else (hooks, the CLI, the SDK, MCP tools) is a thin client that asks the daemon to do work and never holds a storage handle.

#Trust boundaries

flowchart TD
    userBrowser([User browser])
    agentProcess([Coding assistant process])
    hookProcess([Hook / thin-client process])
    daemon([honeycomb daemon, port 3850])
    credFile([~/.deeplake/credentials.json])
    store([Storage: GPU SQL/vector])
    tenant([Org/workspace partition])

    userBrowser -- "OAuth approval over HTTPS" --> daemon
    agentProcess -- "spawns hooks, same OS user" --> hookProcess
    hookProcess -- "read 0600 file" --> credFile
    hookProcess -- "local loopback RPC" --> daemon
    daemon -- "the only path to storage" --> store
    store -- "org/workspace scoped rows" --> tenant

The single most important property of the map is that no process other than the daemon has a line into storage.

Zone Trust level
User browser (OAuth approval page) User-trusted, separate from the assistant
Coding assistant process Host OS user
Hook / thin-client process Same OS user as the assistant
honeycomb daemon Same OS user; the sole storage authority
Credentials file Mode 0600, OS user only
Storage Reached only by the daemon; tenant isolation enforced here, encrypted at rest

Consequences of the chokepoint: a compromised hook can ask the daemon to do work on the user's behalf, but it cannot reach storage directly and cannot read another organization's data, because the daemon re-derives scope from the validated token on every request. SQL construction and escaping live in the daemon, so a thin client cannot smuggle raw SQL to storage. Tenant isolation is enforced at the storage layer, not at a client a user could patch.

#Authentication and authorization

honeycomb separates who you are from what you can do.

Identity comes from an OAuth 2.0 Device Authorization Flow that mints a long-lived, organization-bound token, written to a local file at mode 0600. No password is ever sent, and the short-lived access token is discarded rather than persisted.

Authorization is mode-aware. The daemon runs in one of three modes:

Mode Posture
local No authentication; the daemon binds to localhost. For a single developer.
team Every request needs a valid token or API key; unauthenticated requests get 401; all operations are rate-limited and scoped. The default for a shared deployment.
hybrid Localhost requests are trusted by the TCP peer address from the socket (not the spoofable Host header); remote clients must present a token; missing socket info fails closed.

In team and hybrid modes, four roles (admin, operator, agent, readonly) map to permission sets, and admin, token, diagnostics, source, connector, secret, ontology-mutation, and org or workspace routes always carry an explicit permission check. Remote connectors use named API keys: revocable, stored hashed, prefixed hc_sk_..., printed once at creation, narrowable with an explicit permission list, and bindable to a connector, harness, agent, and allowed projects.

#Token handling at boundaries

The access token is read from disk at hook startup and handed to the daemon. It is never passed as a command-line argument (which would be visible in a process list) and never written to a child process environment. Only the daemon makes the network call to storage, over TLS, with the token in an HTTP header rather than a URL parameter. Token-adjacent log messages are written to standard error, not standard output, so callers that read hook output as structured data cannot parse them.

#Resolving token drift

If a user switches organizations, the stored active organization can disagree with the token's organization claim, which would otherwise query the wrong tenant. The daemon heals this on session start: it decodes the token's organization claim, compares it to the active organization, and re-mints a corrected token if they disagree, before any request reaches storage.

#Scoping and visibility

honeycomb scopes memory in two rings, and both must hold for a row to be visible.

The outer ring is tenancy: organization and workspace, enforced at the storage partition so two workspaces never share a row, partition, or index. The organization and workspace passed with every request are validated server-side against the token's organization claim, so a token minted for one organization cannot read another by editing a header or the credentials file.

The inner ring is the agent: within a workspace, every read and write threads an agent_id, and an agent's roster row carries a read policy:

Policy What the agent sees within its workspace
isolated (fail-closed default) Only its own memories
shared Workspace-global memories plus its own
group Global memories from agents in the same policy group, plus its own

The inner ring is compiled into a SQL clause that every memory query carries, so a new code path either includes it or does not, which makes scoping auditable. The outer ring is enforced beneath it, so even a buggy inner clause cannot cross a workspace boundary.

#The authorization boundary in recall

Recall's candidate channels (full-text, vector, graph traversal, hints) cast a wide net, so the defense is ordering: those channels produce identifiers only, and the scope clause authorizes candidates before any content loads. Every content-bearing stage that follows runs only on the authorized set, so a strong vector hit or a high-degree entity can surface an identifier but cannot leak content past the read policy.

#Fail-closed posture

The subsystem leans toward refusing rather than over-sharing. A malformed caller falls back to isolated rather than widening access. Tenancy, scope, graph policy, mutation gates, and source access all fail closed. Failures return structured errors with enough context to diagnose, rather than silently downgrading. When in doubt, deny.

#Secrets: usable, never readable

If an assistant could read an API key, a single prompt injection could exfiltrate it. honeycomb breaks that link: secrets are encrypted at rest, an assistant can cause them to be used, and an assistant never receives the decrypted values. Secrets are the one class of data that does not live in the shared store; they sit encrypted on the daemon host, so even a full dump of the store yields no credentials.

  • Encryption. Secrets are stored as encrypted files (mode 0600, directories 0700) using an audited, zero-dependency cipher. The key is derived from a machine-bound identifier and scope-bound, so copying the encrypted tree to another machine yields nothing usable.
  • No read path. The API exposes secret names but never values. There is deliberately no "read a secret value" endpoint, through the API, the SDK, MCP, the dashboard, a connector, or diagnostics.
  • The exec model. To use a secret, a caller queues an exec job. The daemon resolves the references, spawns a subprocess with the secrets in its environment under a timeout and a bounded worker pool, and redacts any secret value from the output before the caller sees it. A command can authenticate to an external service without the credential ever passing through the agent's context.

The local secret store generalizes into a single machine-bound encrypted vault that holds typed record classes behind one seam, with each class declaring its read posture (a value-returning setting versus an internal-only secret) as data, so a secret can never be read through the settings path. A credential-copy migration into the vault is non-destructive by construction: it copies the login token and performs zero writes to the original credentials file, which stays authoritative.

#Telemetry egress

honeycomb may emit anonymized operator telemetry from the daemon to an operator-owned analytics backend, for install-funnel attribution and operational health. This is the one outbound boundary other than the daemon-to-storage path, and it is governed by a single non-negotiable rule.

The content versus operation bright line. Telemetry may describe how the tool behaves (counts, durations, versions, states, error classes). It must never describe the content the tool handles (memory or session text, code, prompts, recall queries, file paths, working directory, repository or branch names, organization or workspace names, identities, secrets). The test for any property is the shrug test: would the user shrug if they saw this value in plaintext? If they would lean in and squint, it does not ship.

Boundary invariants worth knowing as a practitioner:

  • Daemon-only emitter through a single chokepoint with a hardcoded allow-list; a structural test asserts the banned set is absent from every event.
  • No item-level egress: no per-memory, per-query, or per-file events, because the cardinality itself is a signal.
  • Tiered consent: operational lifecycle events are opt-out; usage-count events are opt-in. Setting DO_NOT_TRACK=1 or HONEYCOMB_TELEMETRY=0 silences all of it, and an unkeyed build emits nothing.
  • Glass-box: honeycomb telemetry --show renders, in plaintext, exactly what has been and would be sent, so the displayed set is provably the egress set.
  • Anonymous identity: the distinct id is a random per-machine install id, never an email or a content-derived hash, and the ingest key is write-only.

This boundary is independent of capture opt-out: HONEYCOMB_CAPTURE=false governs what your memory records into storage; the telemetry switches govern what operational metadata leaves for the operator.

honeycomb installs hooks into assistant lifecycle events, and each assistant platform enforces its own consent model before running foreign hooks (a trust prompt, a marketplace approval, an operator-controlled config file, or a user-controlled directory). No hook runs silently without an explicit user action, and the install command shows a one-line consent notice before opening the browser for authentication.

#Data classification

Data type At rest In transit Access scope
Access token Plaintext, mode 0600 Bearer header, daemon to backend over TLS OS user only
Secrets Encrypted, decrypted in the daemon on demand TLS Scoped per the secrets rules; never returned
Session traces Encrypted at rest in the tenant partition TLS All members of the organization workspace
Memory summaries Encrypted at rest TLS Organization workspace members
Operator telemetry No content at rest beyond the local event log TLS, write-only ingest key Operator only; opt-out and glass-box; never carries content

Workspace-level isolation is the outer boundary; within a workspace, members share the trace and skill surface by design, with the agent read policy narrowing where the engine enforces it.