Security and auth
Kheish is an execution system. Security decisions affect both the control plane and the runtime itself.Control-plane authentication
The daemon includes built-in bearer authentication for the HTTP control plane. It supports:- an admin token for mutating operations
- an optional read-only token for safe inspection endpoints
--http-auth-mode auto--http-auth-mode bearer--http-auth-mode none
--http-admin-tokenor--http-admin-token-file--http-readonly-tokenor--http-readonly-token-fileKHEISH_DAEMON_ADMIN_TOKENKHEISH_DAEMON_READONLY_TOKEN
auto mode, loopback-only bindings can run without tokens, but non-loopback exposure requires an admin token. Treat none as a local-development mode only.
Connector ingress routes do not reuse these control-plane bearer tokens. Each connector keeps its own authentication model, such as a per-connector HTTP bearer token, a Slack signing secret, or a Telegram secret token.
Daemon-managed connectors still use the normal control-plane auth boundary for their CRUD endpoints. The transport auth they carry is separate from the operator auth used to mutate them.
Runtime safety controls
The main runtime safety controls are:- permission modes and rule scopes
- approval-gated tool execution
- hook-driven policy enforcement
- workspace-root and path validation
- connector-specific authentication such as Slack signing secrets or Telegram secret tokens
Brokered runtime auth
AuthManager remains the root of trust for long-lived deployment credentials such as route secrets, connector secrets, and imported account-backed auth.
At execution time, the daemon does not hand those root credentials directly to agents, sidecars, or delegated work. Instead, it derives three brokered objects:
AuthSubject: the execution identity that is asking for credential-backed workCredentialGrant: the allowed audience for that subject after scope checksCredentialLease: the short-lived opaque lease actually used for one route resolution or one connector sidecar credential request
- provider routes are resolved through short-lived route leases
- child-process external connectors receive short-lived connector leases scoped to explicit env keys
- scoped MCP OAuth resolution, where enabled by a runtime path, uses short-lived leases scoped to one server, slot, and approved scope hash
- revocation is immediate for future resolutions and active leases
- audit can refer to subjects, principals, grants, and leases without exposing the root secret itself
session:demo or agent:agent-7. Those ids are the same identities you will see reflected in audit metadata and runtime auth inspection.
Credential scopes
Kheish separates visibility from credential usage.CapabilityScopecontrols what a session or child can see and callCredentialScopecontrols which auth-backed resources that execution may actually resolve
CredentialScope currently supports:
route_allowroute_denyconnector_allowconnector_denyconnector_credential_allowconnector_credential_denymcp_server_allowmcp_server_deny
- if you scope connectors with
connector_alloworconnector_denyand omitconnector_credential_allow, concrete connector secret env keys default to denied
Inspect and revoke brokered auth
Operator-facing auth inspection is exposed on both the HTTP API and the CLI. HTTP:GET /v1/runtime/auth/subjects/{subject_id}POST /v1/runtime/auth/subjects/{subject_id}/revokeGET /v1/runtime/auth/leases/{lease_id}POST /v1/runtime/auth/leases/{lease_id}/revoke
subject status shows whether a subject has been revoked plus the currently active route, connector, and MCP lease ids. lease status shows the stored lease payload, whether it has been revoked, and whether it is still active.
Account-backed auth status has a separate redacted surface:
Daemon-managed route secrets
The recommended operator path is:- define named routes with
auth_ref - populate those refs through
kheish-daemon secrets ... - start the daemon with
--routes-file ...
auth_ref is the stable daemon-owned identifier for one secret slot. Routes resolve credentials through that identifier instead of inlining API keys in the route file.
Example route file:
state_root and keep reusing it. Replacing it later makes existing encrypted secret slots unreadable.
When account-backed auth is preferable, import it into the same secret slots:
import-codex or OpenAI account-backed auth material.
Operational rules:
- the daemon refuses to start when a configured
auth_refis missing - one
auth_refcan be reused by multiple routes without copying secret material into each route definition runtime getand the secrets endpoints exposeauth_refmetadata, never raw secret valuessecrets seton an existing ref is the standard rotation path for static API-key slots- actual route use still goes through the broker, so route selection can succeed while auth resolution is later denied by the execution’s effective
CredentialScope
Secret storage
Kheish stores daemon-managed route secrets understate_root/auth/global-slots.json.
New writes use the encrypted auth-store envelope when KHEISH_AUTH_STORE_MASTER_KEY or KHEISH_AUTH_STORE_MASTER_KEY_FILE is configured. The loader still accepts the older plaintext JSON shape for backward compatibility, so do not assume an existing state root is already encrypted until it has been rewritten through the current store path.
kheish-daemon secrets list and kheish-daemon secrets get <secret_ref> return slot metadata only:
slot_idprovidermodesummaryupdated_at_ms
- whether the secret is configured
- whether the saved connector points at
inline,env, orsecret_ref - which
secret_reforenvname is bound
KHEISH_AUTH_STORE_MASTER_KEY or KHEISH_AUTH_STORE_MASTER_KEY_FILE. Without one of those, the daemon can still read env-backed config, but it cannot store new runtime-managed secret-store entries.
Built-in MCP catalog credentials use generic opaque slots under mcp.<entry-id>.<credential-env>, for example mcp.linear.LINEAR_API_KEY. Use kheish-daemon mcp auth slots <entry-id> to inspect the slot names and kheish-daemon mcp auth set <entry-id> ... --offline --state-root <state-root> to store or rotate them before startup. Start the daemon with the same state root and auth-store master key. Explicit MCP config can reference custom slots with bearer_token_secret_ref, http_header_secret_refs, and env_secret_refs; stdio MCP servers using env_secret_refs run with a restricted child environment. GitHub’s explicit Docker MCP path uses this same secret-store pattern with mcp.github.GITHUB_PERSONAL_ACCESS_TOKEN; the token is injected into the child process from the daemon store rather than kept in the daemon runtime environment. Restart the daemon after rotating a secret used by an already loaded MCP server.
Spec-compliant HTTP MCP OAuth accounts use OAuth slots under mcp.oauth.<id> and are created with kheish-daemon mcp oauth login. The login flow writes through the daemon account API into the same encrypted auth store, then mcp oauth status, mcp oauth refresh, and runtime auth accounts ... expose only redacted account metadata. OAuth-backed MCP config must reference the slot with oauth_slot_ref, oauth_resource, and oauth_scopes; Kheish rejects scope escalation on refresh and does not let agents consent to broader scopes. Current OAuth-backed MCP config is account plumbing and fail-closed validation only; it does not expose OAuth-backed MCP tools yet.
For container platforms, the same store key can be supplied through KHEISH_AUTH_STORE_MASTER_KEY_FILE. That is the recommended path when your orchestrator already mounts secret files.
The same pattern also exists for control-plane bearer tokens:
KHEISH_DAEMON_ADMIN_TOKEN_FILEKHEISH_DAEMON_READONLY_TOKEN_FILE
Evidence note
- Code verified:
crates/kheish-auth/src/store.rs,crates/kheish-auth/src/manager.rs,crates/kheish-auth/src/broker.rs,crates/kheish-auth/src/backends/openai.rs,crates/kheish-auth/src/backends/anthropic.rs,crates/kheish-auth/src/backends/mcp_oauth.rs,crates/kheish-daemon/src/state.rs,crates/kheish-daemon/src/api/handlers.rs. - CLI verified:
secrets set,secrets import-codex,secrets import-claude-code,runtime auth subject,runtime auth lease,runtime auth accounts,mcp auth, andmcp oauthsurfaces exist. - Daemon live tested: yes for generic MCP OAuth account login/refresh/logout with
scripts/e2e/mcp_oauth_protocol_true_binary.sh; bearer MCP secret-store behavior is covered byscripts/e2e/mcp_secret_store_true_binary.sh; OAuth-backed MCP tool/resource use is not exposed yet. - Vendor manual secret-store check: GitHub explicit Docker MCP config was validated outside the local harness with evidence under
/tmp/kheish-github-mcp-run.7lFCOV: the token stored asmcp.github.GITHUB_PERSONAL_ACCESS_TOKENin Kheish, true daemon startup, OpenAIgpt-5.4, runtimesource: "codex_config", and a realmcp__github__get_metool call. - Provider-specific tested: deterministic account-backend tests exist for OpenAI and Anthropic; validate live Codex/Claude account refresh on your production credential source before relying on it.
Signed external-action audit
Kheish keeps a separate append-only audit ledger for external actions such as provider requests, connector delivery, hooks, and other networked or system-facing boundaries. Each record is signed and chained. The stored fields include:action_id,phase, andkindsession_id,agent_id,run_id, andtool_call_idprincipal_id,parent_principal_id, andgrant_idwhen knowntargetrequest_digestandresponse_digestprev_hash,record_hash,signature_alg,key_id, andsignature
GET /v1/runs/{run_id}/external-actions./target/debug/kheish-daemon runs external-actions <run_id>
- by default the daemon persists its Ed25519 audit signing key at
state_root/audit-signing.key - you can override that with
KHEISH_EXTERNAL_ACTION_AUDIT_SIGNING_KEYorKHEISH_EXTERNAL_ACTION_AUDIT_SIGNING_KEY_FILE
