* fix(secrets): keep store entry kind when rotating a value `secrets store set <NAME> --value-file <path>` resolved the entry kind from the name heuristic whenever no host-policy flag was passed, so rotating the value of an entry created with `--kind secret` under a name the heuristic does not classify as sensitive silently converted it into a readable `env` entry and deleted its `--allow-host` allowlist. `import` classified every entry from its name for the same reason. Both paths now inherit the stored kind, and that inheritance is resolved inside the authoritative store write transaction rather than captured before the CLI awaits its value or its confirmation. A protection change committed while one of those waits is pending is therefore no longer overwritten by the pending write, and the value it carries lands under the newer policy instead of reaching agent subprocesses as plaintext. Because a kind resolved at write time can invalidate a value the CLI already accepted, `import` now hands its whole batch to a single store-owned write. `writeSecretStoreEntries` resolves every live kind and validates every resulting entry inside one transaction before it writes any of them, so an entry that a concurrent protection change turns into an empty secret still fails the command with nothing committed, matching the existing no-write-on-validation-failure contract. An explicit `--kind` still overrides both the stored kind and the name heuristic in either direction. (cherry picked from commit 66a8c01c8db76bf63ab79c506880f462856b2d1e) * fix(secrets): satisfy CI pools, formatters, and assertion ratchet - Run the kind-inheritance purge through the expiry kernel directly so it does not require the host-broker state worker (the CLI project executes test files off the main thread). - Replace uncommented kind casts with runtime narrowing for the assertion SAFETY ratchet; reformat to oxfmt. Co-authored-by: yetval <yetvald@gmail.com> * chore(ci): rerun checks * ci: retrigger checks for flaky shard reruns * ci: retrigger checks (flaky infra shards) * test(ci): dedupe pdf-tool.resources in database worker core paths670e3fb4ea(#161270) re-added src/agents/tools/pdf-tool.resources.test.ts to databaseWorkerCoreTestFiles, which already listed it (16b17b22eb). The changed-node shard planner now rejects repeated files in a split timing generation, so preflight threw 'split timing generation repeats files for core-runtime-infra-storage-state' for every PR touching any non-README path. * fix(secrets): enforce literal input safety at commit Carry argv provenance to the store transaction and refuse literal values when kind inheritance resolves to a secret. Preserve explicit env reclassification, cover concurrent protection, and clarify the set/import kind rules. Strengthen rotation-value, committed-kind output, and redacted batch no-write regressions. Existing Gateway writer paths remain unchanged. Co-authored-by: zachisfine <131436334+zachisfine@users.noreply.github.com> Co-authored-by: yetval <yetvald@gmail.com> --------- Co-authored-by: yetval <yetvald@gmail.com> Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: zachisfine <131436334+zachisfine@users.noreply.github.com>
16 KiB
| summary | read_when | title | ||||
|---|---|---|---|---|---|---|
| CLI reference for `openclaw secrets` (store, reload, audit, configure, apply) |
|
Secrets CLI |
openclaw secrets
Manage SecretRefs and keep the active runtime snapshot healthy.
| Command | Role |
|---|---|
reload |
Gateway RPC (secrets.reload): re-resolves refs and atomically publishes the owner-aware runtime snapshot (no config writes); eligible owner failures may publish as cold or stale warnings |
store |
Manages team-scoped secret and environment values in the local shared state SQLite database |
audit |
Read-only scan of config/auth/generated-model stores and legacy residues for plaintext, unresolved refs, and precedence drift (exec refs skipped unless --allow-exec) |
configure |
Interactive planner for provider setup, target mapping, and preflight (requires a TTY) |
apply |
Executes a saved plan (--dry-run validates only and skips exec checks by default; write mode rejects exec-containing plans unless --allow-exec), then scrubs targeted plaintext residues |
Recommended operator loop:
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 reload
If your plan includes exec SecretRefs/providers, pass --allow-exec on both the dry-run and write apply commands. If the closing audit --check still reports plaintext findings, update the remaining reported target paths and rerun the audit.
Exit codes for CI/gates:
audit --checkreturns1on findings.- Unresolved refs return
2(regardless of--check). - Store validation and disclosure-policy failures return
2. store getreturns3when the name is missing.
Related: Secrets Management · 1Password plugin · SecretRef Credential Surface · Security
Shared secret store
openclaw secrets store writes directly to the local shared state database. The store is Gateway-wide and team-scoped, and --scope team is the only accepted value. --scope me exits 2 with Identity scope is not supported yet; use --scope team.
Entries also arrive from Settings -> Secrets in the Control UI, and from the agent's secrets tool. That tool asks you to type a credential into a masked prompt. It stores the credential without the value reaching the model.
openclaw secrets store list
openclaw secrets store set <NAME>
openclaw secrets store get <NAME>
openclaw secrets store rm <NAME>...
openclaw secrets store import [--from <file>]
Naming and value rules:
- Names must match
^[A-Z][A-Z0-9_]{0,127}$. - Values are limited to 64 KiB (65,536 UTF-8 bytes). An oversized value exits
2whether it arrives from stdin,--value, or--value-file. - A
secretentry may not be empty, because an empty credential cannot be diagnosed later.getrefuses secret kinds, and listings mask them.enventries may be empty. - Known redaction placeholders such as
__OPENCLAW_REDACTED__cannot be stored as values. CLIsetandimportskip redacted inputs for existing usable entries with an explicit unchanged message; a placeholder without a usable existing entry exits2. --kind secret|envexplicitly changes an entry's kind. Otherwisesetandimportpreserve the entry's current kind when saving, including protection changes made while input or confirmation is pending. Only new names use automatic detection: names ending in a common credential suffix such as_API_KEY,_TOKEN,_PASSWORD,_PRIVATE_KEY, or_SECRETbecomesecret, and other names becomeenv.
Set values safely
--value is accepted only when the resolved kind is env:
openclaw secrets store set LOG_LEVEL --kind env --value debug
For secret values, --value is refused with exit code 2 because command-line arguments can leak through shell history and process listings. It is also refused if another writer changes the entry to secret before the value is saved. Explicit --kind env still reclassifies the entry. Use one of the three safe inputs instead:
- Pipe stdin when stdin is not a TTY.
- Pass
--value-file <path>.--value-file -means stdin. - Run interactively and enter the value in the no-echo prompt.
Examples:
op read 'op://Engineering/OpenAI/apiKey' | \
openclaw secrets store set OPENAI_API_KEY --kind secret
openclaw secrets store set TLS_PRIVATE_KEY \
--kind secret \
--value-file ./client-key.pem
set is idempotent and updates an existing name. Add --dry-run to validate and preview the operation without writing. A successful write reminds you to run openclaw secrets reload before a config-referenced value can take effect.
audit reports previously stored or resolved placeholders as PLACEHOLDER_VALUE
and counts them as unresolved credentials (exit 2). For a corrupt store-backed
Gateway token, run openclaw doctor --fix, restart the Gateway, and reconnect or
re-pair devices. See Gateway token recovery.
Secret egress substitution fails closed until each secret has at least one exact allowed host. Bind or replace hosts with repeatable --allow-host flags. This policy-only form does not ask for or replace an existing secret value:
openclaw secrets store set OPENAI_API_KEY --allow-host api.openai.com
openclaw secrets store set SERVICE_TOKEN \
--allow-host api.example.com \
--allow-host uploads.example.com
openclaw secrets store set SERVICE_TOKEN --clear-allowed-hosts
Hosts are normalized to lowercase ASCII/punycode. Schemes, paths, ports, and wildcards are rejected. store list shows allowed hosts because they are policy metadata, not secret material.
Read values
openclaw secrets store list --json
openclaw secrets store list --plain
openclaw secrets store get LOG_LEVEL
Secret values never appear in human, --json, or --plain output. store get refuses a secret entry as write-only by design and exits 2. It exits 3 when the name does not exist. Environment-kind values are readable.
Team-scoped env entries reach Gateway-hosted commands run by OpenClaw's own exec tool, including OpenClaw Code Mode calls into openclaw:core:exec and Codex gateway_exec. Explicit per-call env wins over store values. Sandbox, remote node, ACP, and Codex-native shell execution do not receive them. secret entries stay out of subprocesses by default. With secrets.egressProxy.enabled: true, Gateway-hosted exec receives only authenticated sentinels and the Gateway replaces them at HTTPS egress. See Secret egress proxy.
Remove values
openclaw secrets store rm OLD_TOKEN
openclaw secrets store rm OLD_TOKEN LEGACY_PASSWORD --yes
openclaw secrets store rm OLD_TOKEN --dry-run
Removal is idempotent, so a missing name succeeds quietly. Without --yes, the CLI asks for confirmation. Removed rows are soft-deleted and purged after 30 days.
Import dotenv files
Import dotenv-format assignments from a regular file or stdin:
openclaw secrets store import --from .env
openclaw secrets store import --from .env --dry-run
openclaw secrets store import --from .env --yes
op read 'op://Engineering/service-account/dotenv' | openclaw secrets store import --yes
The importer supports quoted values and multiline quoted values such as PEM keys. Use --yes to skip confirmation and --dry-run to inspect the import without writing. Like store set, import preserves an existing entry's kind and uses the name-based rule only for new names. Pass --kind secret|env to explicitly reclassify all imported entries.
The store CLI commands do not accept --url or --token and do not route through the Gateway. The Control UI uses the admin-scoped secrets.store.* RPC methods instead. Those methods refresh the runtime automatically when a changed name is referenced by active config.
Reload runtime snapshot
openclaw secrets reload
openclaw secrets reload --json
openclaw secrets reload --url ws://127.0.0.1:18789 --token <token>
Uses gateway RPC method secrets.reload. Healthy owners refresh independently. Eligible failed owners become stale only when their ref identities, provider definitions, and complete non-secret owner contract are unchanged. New or changed failures become cold. This degraded activation succeeds and reports warningCount. Strict or unmapped failures return an error and preserve the previously active snapshot.
Options: --url <url>, --token <token>, --timeout <ms>, --json.
Audit
Scans OpenClaw state for:
- plaintext secret storage
- unresolved refs
- precedence drift (auth profile store credentials shadowing
openclaw.jsonrefs) - store residue (a team store value duplicated by plaintext in
openclaw.json) - generated
agents/*/agent/models.jsonresidues (providerapiKeyvalues and sensitive provider headers) - legacy residues (legacy auth store entries, OAuth reminders)
The .env scan covers the effective state directory and the directory containing the active config. When both paths name the same file, it is scanned once.
Sensitive provider header detection is name-heuristic based: it flags headers whose name matches common auth/credential fragments (authorization, x-api-key, token, secret, password, credential).
Doctor and secrets audit share the plaintext classification for openclaw.json. Known non-secret provider API-key markers such as ollama-local, SecretRefs, and non-sensitive provider headers do not produce plaintext warnings. Real plaintext keys still do.
openclaw secrets audit
openclaw secrets audit --check
openclaw secrets audit --json
openclaw secrets audit --allow-exec
Report shape:
status:clean | findings | unresolvedresolution:refsChecked,skippedExecRefs,resolvabilityCompletesummary:plaintextCount,unresolvedRefCount,shadowedRefCount,storeResidueCount,legacyResidueCount- finding codes:
PLAINTEXT_FOUND,REF_UNRESOLVED,REF_SHADOWED,STORE_PLAINTEXT_RESIDUE,LEGACY_RESIDUE
Configure (interactive helper)
Build provider and SecretRef changes interactively, run preflight, and optionally apply:
openclaw secrets configure
openclaw secrets configure --plan-out /tmp/openclaw-secrets-plan.json
openclaw secrets configure --apply --yes
openclaw secrets configure --providers-only
openclaw secrets configure --skip-provider-setup
openclaw secrets configure --agent ops
openclaw secrets configure --json
Flow: provider setup first (add/edit/remove secrets.providers aliases), then credential mapping (select fields, assign {source, provider, id} refs), then preflight and optional apply.
For env and store refs, no provider entry is required when provider matches that source's effective default: secrets.defaults.env or secrets.defaults.store, falling back to default when unset. Other aliases and all file/exec refs require a matching secrets.providers entry.
Flags:
--providers-only: configuresecrets.providersonly, skip credential mapping--skip-provider-setup: skip provider setup, map credentials to existing providers--agent <id>: scope auth profile target discovery and writes to one agent store--allow-exec: allow exec SecretRef checks during preflight/apply (may execute provider commands)
--providers-only and --skip-provider-setup cannot be combined.
Notes:
- Requires an interactive TTY.
- Targets secret-bearing fields in
openclaw.jsonplus the selected agent's auth profile store. The canonical supported surface is SecretRef Credential Surface. - Supports creating new auth profile mappings directly in the picker flow.
- Runs preflight resolution before apply.
- Generated plans enable
scrubEnvandscrubAuthProfilesForProviderTargets.scrubLegacyAuthJsonstays disabled, because Doctor owns legacyauth.jsonmigration. Apply is one-way for scrubbed plaintext values. --plan-outrefuses to create a plan whose UTF-8 serialized form exceeds 16 MiB (16,777,216 bytes), matching theapply --frominput limit.- Without
--apply, the CLI still promptsApply this plan now?after preflight. - With
--apply(and no--yes), the CLI prompts an extra irreversible-migration confirmation. --jsonprints the plan + preflight report, but still requires an interactive TTY.
Exec provider safety
Package managers often expose symlinked command paths. Resolve the real binary path (for example with realpath "$(command -v vault)") and configure that absolute, non-symlink path. Use trustedDirs to restrict executables to approved directories. Run openclaw config validate on the Gateway host to check manual exec command paths without executing providers. On Windows, provider paths fail closed when ACL verification is unavailable, with no provider-level bypass.
Apply a saved plan
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --allow-exec
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run --allow-exec
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --json
--dry-run validates preflight without writing files. Exec SecretRef checks are skipped by default in dry-run. Write mode rejects plans containing exec SecretRefs/providers unless --allow-exec. Use --allow-exec to opt in to exec provider checks/execution in either mode.
--from must point to a regular file no larger than 16 MiB (16,777,216 bytes). The byte limit applies to the complete serialized file, including whitespace.
What apply may update:
openclaw.json(SecretRef targets + provider upserts/deletes)- auth profile store (provider-target scrubbing)
- legacy
auth.jsonresidues .envfiles in the effective state and active-config directories, for known secret keys whose values were migrated
Plan contract details (allowed target paths, validation rules, failure semantics): Secrets Apply Plan Contract.
Why no rollback backups
secrets apply intentionally does not write rollback backups containing old plaintext values. Safety comes from strict preflight plus atomic-ish apply, with best-effort in-memory restore on failure.