OpenClaw Secrets Guide: SecretRefs and What a Clean Audit Misses
Your agent can read its own config file. That one fact is the reason SecretRefs exist, and most people migrate to them halfway.
OpenClaw keeps provider keys and bot tokens in openclaw.json unless you tell it otherwise. Plaintext still works, and SecretRefs are opt-in per credential, so nothing forces the move. The official docs are blunt about why you should make it anyway: plaintext credentials "remain agent-readable if they sit in files the agent can inspect," and they name openclaw.json, the auth-profile store, .env and the generated agents/*/agent/models.json files. An agent with a file-read tool and a prompt injection in a web page is all it takes. The guides that rank for this topic cover the provider types and the audit, configure, apply loop well. They stop at the moment the audit comes back clean. This page starts there, because a passing audit leaves real keys behind in places it was never designed to look.
What a SecretRef Looks Like
Every SecretRef has the same three fields, whatever the backend:
{ source: "env" | "file" | "exec", provider: "default", id: "..." }source picks the backend. provider names a provider block you defined under secrets.providers. id is the lookup key, and its grammar depends on the source: an uppercase variable name for env (OPENAI_API_KEY), an absolute JSON pointer for a JSON file (/providers/openai/apiKey), or a path-like string for exec. Newer releases add a fourth source, store, backed by a local SQLite store you manage with openclaw secrets store.
{
secrets: {
providers: {
default: { source: "env" },
filemain: { source: "file", path: "~/.openclaw/secrets.json", mode: "json" },
op_openai: {
source: "exec",
command: "/opt/homebrew/bin/op",
allowSymlinkCommand: true,
trustedDirs: ["/opt/homebrew"],
args: ["read", "op://Personal/OpenClaw API Key/password"],
passEnv: ["HOME"],
jsonOnly: false
}
}
}
}The exec block is the one that trips people up on a Mac. Homebrew's op is a symlink, the command has to be an absolute path, and OpenClaw runs it directly with no shell. Without allowSymlinkCommand and trustedDirs it refuses. Without passEnv the child process gets almost no environment, so op cannot find its own session. For a headless gateway, the 1Password page recommends a service account (OP_SERVICE_ACCOUNT_TOKEN) scoped to only the vault items the gateway needs.
My preference, for what it is worth: exec to a password manager for model keys, env for everything else. The security best practices guide on this site shows the older pattern of wrapping the gateway in op run, which keeps keys out of the config file and leaves the gateway with no idea which fields are supposed to be secret. SecretRefs let the audit know.
The Migration Loop
The CLI reference gives this as the operator loop, and I would not reorder any of it:
openclaw secrets audit --check
openclaw secrets configure --plan-out /tmp/openclaw-secrets-plan.json
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 reloadaudit is read-only and exits 1 on findings, 2 on unresolved refs, which makes it usable in a script. configure is interactive and needs a real TTY: providers first, then field mapping, then a preflight. apply writes the plan, swaps files atomically and scrubs the plaintext it replaced from openclaw.json, the auth-profile store and legacy auth.json residue. reload asks the running gateway to re-resolve everything.
That last step matters more than it looks. Secrets resolve eagerly, at activation, into an in-memory snapshot. Telegram sends and Discord replies read from the snapshot and do not re-resolve per message. Rotate a key in 1Password and the gateway keeps using the old one until you reload or restart.
Hole One: Exec Refs Were Never Checked
By default, audit skips exec SecretRefs to avoid running commands with side effects. So does apply --dry-run. Your 1Password ref can have a typo in the item name and both commands will pass.
openclaw secrets audit --check --allow-execRun that once, by hand, after any change to an exec provider. Write mode is stricter (it rejects a plan containing exec refs unless you pass --allow-exec), but people who see a clean dry run tend to assume the real run will be clean too.
Hole Two: Refs on Surfaces That Are Turned Off
OpenClaw only insists on resolving refs for surfaces that are actually active. An unresolved ref on an enabled channel blocks startup, which is what you want. An unresolved ref on a disabled channel produces a diagnostic, SECRETS_REF_IGNORED_INACTIVE_SURFACE, and the gateway starts normally. The docs list other inactive cases: a web search provider you have not selected, or SSH auth material while the sandbox backend is something other than ssh (the sandbox guide covers when you would switch).
Which means a broken ref can sit in your config for months and fail the afternoon you enable the Discord account you parked. Grep the startup log for that diagnostic code after every migration. It is a list of future outages.
Hole Three: The Copies
The audit scans the live files. It does not scan your backups.
If you run the nightly script from the backup and migration guide, you keep fourteen encrypted tarballs of ~/.openclaw, and every one written before migration day contains openclaw.json with your keys in it. Encryption helps. The keys are still valid. OpenClaw itself takes the opposite position on purpose: its one-way safety policy says it does not write rollback backups containing historical plaintext secret values. The docs put the general rule plainly. Backups, copied configs and old generated model catalogs "stay production secrets until deleted, moved outside the agent trust boundary, or isolated separately."
The only clean fix is rotation. Once the refs work, issue new keys at each provider, point the refs at them, reload, and revoke the old ones. The tarballs become harmless without anyone touching them. Also check the copy of openclaw.json you made by hand before some risky edit, any config you pasted into a gist while asking for help, and the workspace itself, since agents copy keys into notes while debugging.
What SecretRefs Do Not Cover
Runtime-minted and rotating credentials, including OAuth refresh material, are deliberately excluded from SecretRef resolution, and combining an OAuth-mode auth profile with SecretRef input fails activation. If a provider is on OAuth, leave it there. The official credential-surface reference is the list to check before you assume a field is supported.
When Reload Fails
Startup and reload fail differently. At startup, an unresolvable active ref aborts the gateway, which is the failure you notice immediately. After the gateway is healthy, a failed reload keeps the last-known-good snapshot and emits SECRETS_RELOADER_DEGRADED once, then SECRETS_RELOADER_RECOVERED once the next activation succeeds. Repeated failures in between only log warnings. Your agent keeps answering on the old keys, which feels fine right up until you revoke them. If the agent goes quiet after a rotation, the gateway doctor guide is the place to start.
Common Failure Modes
Audit is clean but the gateway will not start
An exec ref was skipped. Run openclaw secrets audit --check --allow-exec.
Exec provider refuses to run op or vault
Homebrew binaries are symlinks. Set allowSymlinkCommand: true and add /opt/homebrew to trustedDirs.
Rotated key, agent still uses the old one
The snapshot is resolved at activation. Run openclaw secrets reload.
Enabling a channel broke startup
Its ref was never resolved while the channel was off. Look for SECRETS_REF_IGNORED_INACTIVE_SURFACE in older logs.
Final Verdict
Migrate every supported credential, bot tokens included. The docs only credit SecretRefs with shrinking the blast radius once all of them are moved. Run the audit with --allow-exec. Read the inactive-surface diagnostics. Then rotate, since the old keys live on in every backup you made before today. The pre-upgrade snapshots from the upgrade guide are on that list too.
Ready to build?
Get the OpenClaw Starter Kit — config templates, 5 production-ready skills, deployment checklist. Go from zero to running in under an hour.
$14 $6.99
Get the Starter Kit →Also in the OpenClaw store
Get the free OpenClaw quickstart guide
Step-by-step setup. Plain English. No jargon.