OpenClaw Secrets: Keep Agent Credentials Out of Prompts and Commits
Read from search, close with the playbook
If this post helped, here is the fastest path into the full operator setup.
Search posts do the first job. The preview, homepage, and full playbook show how the pieces fit together when you want the whole operating system.
Credentials are one of the easiest ways to turn a useful AI agent into a production liability. A rushed operator pastes an API key into a config file. A model token lands in a repo. A teammate asks the agent to “remember” a service account. The system still works, so nobody notices until a commit, log, or prompt transcript becomes a secret-management incident.
OpenClaw’s SecretRef system is built for a more boring, safer pattern: keep supported credentials as references, resolve them during activation, and run the gateway from an in-memory snapshot instead of scattering raw keys across working files. Plaintext still works, and SecretRefs are opt-in per credential, but for any long-lived operator box I would treat SecretRefs as the default for static secrets.
This is not about making secrets magical. It is about moving credentials out of places humans and agents casually copy, summarize, commit, and paste. If an agent needs to operate across providers, channels, and tools, the operator has to decide where secret material belongs. “In the prompt” is never that place. “In random config committed to Git” is not much better.
The operator rule: references in config, values in the secret backend
The core contract is small. OpenClaw uses one SecretRef object shape across supported fields:
{ source: "env" | "file" | "exec", provider: "default", id: "..." } That shape lets a config file point to a value without storing the value directly. The docs define three source types. env reads from an environment variable. file reads from a configured local file provider and can resolve JSON pointers. exec runs a configured absolute binary with a structured request and reads the response from stdout.
Here is the simplest environment-backed model credential example:
{
secrets: {
providers: {
default: { source: "env" }
}
},
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
models: [{ id: "gpt-5", name: "gpt-5" }],
apiKey: { source: "env", provider: "default", id: "OPENAI_API_KEY" }
}
}
}
} The useful part is not the syntax. The useful part is the boundary. The OpenClaw config can describe which credential should be used, while the actual secret value stays in the environment, a local secret file, or a resolver command. That is a much healthier habit than pasting keys into docs, prompts, tickets, or committed config.
SecretRefs resolve before runtime work starts
The runtime model matters. OpenClaw resolves SecretRefs into an in-memory runtime snapshot. Resolution is eager during activation, not lazy on request paths. Startup fails fast when an effectively active SecretRef cannot be resolved. Reload is atomic: full success swaps in the new snapshot, otherwise the gateway keeps the last-known-good snapshot.
That is exactly what I want from production secret handling. A broken secret backend should not surprise the system halfway through a customer reply. The gateway either starts with a valid active snapshot, or it refuses to activate the broken surface. Runtime requests and outbound delivery paths read from the active snapshot; they do not re-resolve SecretRefs on every send.
That also gives operators a clean mental model. After rotating a backend secret, refresh the snapshot deliberately:
openclaw secrets reload
openclaw secrets reload --json The CLI docs say openclaw secrets reload calls the gateway secrets.reload RPC. If resolution fails, the gateway keeps the last-known-good snapshot and returns an error instead of partially activating a bad state.
Active-surface filtering prevents false startup failures
OpenClaw only validates SecretRefs on effectively active surfaces. Enabled surfaces must resolve. Inactive surfaces do not block startup or reload, and unresolved inactive refs emit a non-fatal diagnostic with SECRETS_REF_IGNORED_INACTIVE_SURFACE.
This is more than a convenience detail. Real agent boxes accumulate disabled channels, old provider entries, alternate web-search keys, and sandbox settings that only matter under specific backends. If every dormant ref blocked startup, secret migration would become a trap. Active-surface filtering lets the gateway care about the credentials that can actually affect the current runtime.
The docs call out examples: disabled channel or account entries, top-level channel credentials no enabled account inherits, disabled tool or feature surfaces, web-search provider keys that are not selected, sandbox SSH auth material when the effective backend is not ssh, and gateway auth refs that lose to another configured auth surface.
Gateway auth surfaces also log explicit state. When SecretRefs are configured on gateway auth or remote auth token/password fields, startup and reload report whether each surface is active or inactive with SECRETS_GATEWAY_AUTH_SURFACE. That is the kind of diagnostic that saves you from guessing why a credential was ignored.
If you want the operator version of this, secrets, model auth, memory, approvals, cron discipline, and production reporting in one place, get ClawKit here.
Audit before you trust the box
The most practical command in the whole workflow is the audit. It checks for plaintext secret storage, unresolved refs, precedence drift, generated model residues, and legacy auth residues. The docs list surfaces such as openclaw.json, auth-profiles.json, .env, and generated agents/*/agent/models.json files.
openclaw secrets audit
openclaw secrets audit --check
openclaw secrets audit --json
openclaw secrets audit --allow-exec audit --check is useful for gates because it exits non-zero on findings. Unresolved refs have their own higher-priority non-zero exit behavior. The report includes status values like clean, findings, and unresolved, plus counts for plaintext, unresolved refs, shadowed refs, and legacy residues.
By default, audit skips exec SecretRef resolvability checks to avoid side effects from provider commands. If you want audit to execute exec providers, opt in with --allow-exec. That explicit consent is a good pattern: command-backed secret resolution can be powerful, but it should not run invisibly inside a routine read-only check.
Use configure and apply as a migration workflow
The recommended CLI loop is straightforward:
openclaw secrets audit --check
openclaw secrets configure
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets audit --check
openclaw secrets reload configure is an interactive planner. It sets up providers first, maps supported secret-bearing fields second, runs preflight, and can apply immediately. It can configure providers only, skip provider setup when you already have providers, or scope auth-profiles.json target discovery to an agent with --agent.
apply executes a saved plan. Dry-run validates without writing. Write mode rejects plans containing exec SecretRefs or providers unless --allow-exec is set. If your plan includes exec refs, pass --allow-exec on both dry-run and real apply.
The important warning: applying a secret plan is intentionally one-way for scrubbed plaintext. OpenClaw does not write rollback backups containing historical plaintext secret values. The safety model is preflight, runtime activation validation, atomic file replacement, and best-effort restore on failure, not “save another copy of the secret somewhere else.”
Plan files are strict for a reason
openclaw secrets apply enforces a strict plan contract. A plan has a targets array, and each target must match a recognized target type and normalized path shape. Forbidden path segments such as __proto__, prototype, and constructor are rejected. Provider or account IDs must match the encoded path. auth-profiles.json targets require an agentId.
{
version: 1,
protocolVersion: 1,
targets: [
{
type: "models.providers.apiKey",
path: "models.providers.openai.apiKey",
pathSegments: ["models", "providers", "openai", "apiKey"],
providerId: "openai",
ref: { source: "env", provider: "default", id: "OPENAI_API_KEY" }
}
]
} If a target is invalid, apply fails before mutating configuration. That sounds strict because it is supposed to be strict. A migration tool that rewrites credential paths should be boring, predictable, and hard to trick into writing somewhere unexpected.
Auth profiles can use refs too
Model authentication is another place where operators accidentally spread secrets. OpenClaw supports OAuth and API keys for model providers, but for always-on gateway hosts the authentication docs recommend API keys as the predictable option. Put the key on the gateway host, verify with openclaw models status, and if the gateway runs under systemd or launchd, keep daemon-readable values in ~/.openclaw/.env.
For auth profile storage, static credentials can use refs. API-key credentials can use keyRef, and token credentials can use tokenRef. Token profiles still obey expiration semantics: expires is optional, but if present it must be finite and greater than zero; expired or invalid values make the profile ineligible. A tokenRef does not bypass expiration validation.
The docs also draw a line around runtime-minted, rotating, and OAuth refresh material. Those are intentionally excluded from read-only SecretRef resolution. That boundary is healthy. SecretRefs are for static credential references, not a promise to turn every provider’s refresh behavior into a copyable config object.
The practical checklist
- Do not paste keys into prompts, chat threads, markdown runbooks, or tickets.
- Replace supported plaintext credentials with SecretRefs for
env,file, orexecproviders. - Run
openclaw secrets audit --checkbefore and after migration. - Use
openclaw secrets apply --dry-runbefore write mode. - Pass
--allow-execonly when you intentionally want exec providers to run. - Reload the secrets snapshot after backend rotation with
openclaw secrets reload. - Use
openclaw models status --checkto catch expired or missing provider auth before agents fail mid-work.
Secrets discipline is not a nice-to-have for autonomous agents. Agents summarize context, call tools, write files, open PRs, run crons, and talk in channels. The safest credential is the one the agent can reference operationally without ever needing to quote back to a human or leak through a commit.
OpenClaw’s SecretRef system gives you that operating shape: references in config, strict activation, atomic reload, audit visibility, and one-way scrubbing instead of secret-hoarding backups. It is boring infrastructure, which is exactly what credential handling should be.
Want the complete guide? Get ClawKit — $9.99