{"id":611,"date":"2026-03-21T22:52:56","date_gmt":"2026-03-21T14:52:56","guid":{"rendered":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/gateway-secrets\/"},"modified":"2026-03-21T23:28:49","modified_gmt":"2026-03-21T15:28:49","slug":"gateway-secrets","status":"publish","type":"post","link":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/gateway-secrets\/","title":{"rendered":"Secrets Management"},"content":{"rendered":"<h1>Secrets Management<\/h1>\n<h1>Secrets management<\/h1>\n<p>OpenClaw supports additive SecretRefs so supported credentials do not need to be stored as plaintext in configuration.<\/p>\n<p>Plaintext still works. SecretRefs are opt-in per credential.<\/p>\n<h2>Goals and runtime model<\/h2>\n<p>Secrets are resolved into an in-memory runtime snapshot.<\/p>\n<ul>\n<li>Resolution is eager during activation, not lazy on request paths.<\/li>\n<li>Startup fails fast when an effectively active SecretRef cannot be resolved.<\/li>\n<li>Reload uses atomic swap: full success, or keep the last-known-good snapshot.<\/li>\n<li>Runtime requests read from the active in-memory snapshot only.<\/li>\n<li>Outbound delivery paths also read from that active snapshot (for example Discord reply\/thread delivery and Telegram action sends); they do not re-resolve SecretRefs on each send.<\/li>\n<\/ul>\n<p>This keeps secret-provider outages off hot request paths.<\/p>\n<h2>Active-surface filtering<\/h2>\n<p>SecretRefs are validated only on effectively active surfaces.<\/p>\n<ul>\n<li>Enabled surfaces: unresolved refs block startup\/reload.<\/li>\n<li>Inactive surfaces: unresolved refs do not block startup\/reload.<\/li>\n<li>Inactive refs emit non-fatal diagnostics with code <code>SECRETS_REF_IGNORED_INACTIVE_SURFACE<\/code>.<\/li>\n<\/ul>\n<p>Examples of inactive surfaces:<\/p>\n<ul>\n<li>Disabled \u6e20\u9053\/account entries.<\/li>\n<li>Top-level \u6e20\u9053 credentials that no enabled account inherits.<\/li>\n<li>Disabled tool\/feature surfaces.<\/li>\n<li>Web search provider-specific keys that are not selected by <code>tools.web.search.provider<\/code>.<br \/>\n  In auto mode (provider unset), keys are consulted by precedence for provider auto-detection until one resolves.<br \/>\n  After selection, non-selected provider keys are treated as inactive until selected.<\/li>\n<li>Sandbox SSH auth material (<code>agents.defaults.sandbox.ssh.identityData<\/code>,<br \/>\n  <code>certificateData<\/code>, <code>knownHostsData<\/code>, plus per-agent overrides) is active only<br \/>\n  when the effective sandbox backend is <code>ssh<\/code> for the default agent or an enabled agent.<\/li>\n<li><code>gateway.remote.token<\/code> \/ <code>gateway.remote.password<\/code> SecretRefs are active if one of these is true:<\/li>\n<li><code>gateway.mode=remote<\/code><\/li>\n<li><code>gateway.remote.url<\/code> is configured<\/li>\n<li><code>gateway.tailscale.mode<\/code> is <code>serve<\/code> or <code>funnel<\/code><\/li>\n<li>In local mode without those remote surfaces:\n<ul>\n<li><code>gateway.remote.token<\/code> is active when token auth can win and no env\/auth token is configured.<\/li>\n<li><code>gateway.remote.password<\/code> is active only when password auth can win and no env\/auth password is configured.<\/li>\n<\/ul>\n<\/li>\n<li><code>gateway.auth.token<\/code> SecretRef is inactive for startup auth resolution when <code>OPENCLAW_GATEWAY_TOKEN<\/code> (or <code>CLAWDBOT_GATEWAY_TOKEN<\/code>) is set, because env token input wins for that runtime.<\/li>\n<\/ul>\n<h2>Gateway \u7f51\u5173 auth surface diagnostics<\/h2>\n<p>When a SecretRef is configured on <code>gateway.auth.token<\/code>, <code>gateway.auth.password<\/code>,<br \/>\n<code>gateway.remote.token<\/code>, or <code>gateway.remote.password<\/code>, \u7f51\u5173 startup\/reload logs the<br \/>\nsurface state explicitly:<\/p>\n<ul>\n<li><code>active<\/code>: the SecretRef is part of the effective auth surface and must resolve.<\/li>\n<li><code>inactive<\/code>: the SecretRef is ignored for this runtime because another auth surface wins, or<br \/>\n  because remote auth is disabled\/not active.<\/li>\n<\/ul>\n<p>These entries are logged with <code>SECRETS_GATEWAY_AUTH_SURFACE<\/code> and include the reason used by the<br \/>\nactive-surface policy, so you can see why a credential was treated as active or inactive.<\/p>\n<h2>Onboarding reference preflight<\/h2>\n<p>When onboarding runs in interactive mode and you choose SecretRef storage, OpenClaw runs preflight validation before saving:<\/p>\n<ul>\n<li>Env refs: validates env var name and confirms a non-empty value is visible during setup.<\/li>\n<li>Provider refs (<code>file<\/code> or <code>exec<\/code>): validates provider selection, resolves <code>id<\/code>, and checks resolved value type.<\/li>\n<li>Quickstart reuse path: when <code>gateway.auth.token<\/code> is already a SecretRef, onboarding resolves it before probe\/dashboard bootstrap (for <code>env<\/code>, <code>file<\/code>, and <code>exec<\/code> refs) using the same fail-fast gate.<\/li>\n<\/ul>\n<p>If validation fails, onboarding shows the error and lets you retry.<\/p>\n<h2>SecretRef contract<\/h2>\n<p>Use one object shape everywhere:<\/p>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{ source: &#8220;env&#8221; | &#8220;file&#8221; | &#8220;exec&#8221;, provider: &#8220;default&#8221;, id: &#8220;&#8230;&#8221; }<\/p>\n<pre><code>\n### `source: &quot;env&quot;`\n\n```json5  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\n{ source: &quot;env&quot;, provider: &quot;default&quot;, id: &quot;OPENAI_API_KEY&quot; }\n<\/code><\/pre>\n<p>Validation:<\/p>\n<ul>\n<li><code>provider<\/code> must match <code>^[a-z][a-z0-9_-]{0,63}$<\/code><\/li>\n<li><code>id<\/code> must match <code>^[A-Z][A-Z0-9_]{0,127}$<\/code><\/li>\n<\/ul>\n<h3><code>source: \"file\"<\/code><\/h3>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{ source: &#8220;file&#8221;, provider: &#8220;filemain&#8221;, id: &#8220;\/providers\/openai\/apiKey&#8221; }<\/p>\n<pre><code>\nValidation:\n\n* `provider` must match `^[a-z][a-z0-9_-]{0,63}$`\n* `id` must be an absolute JSON pointer (`\/...`)\n* RFC6901 escaping in segments: `~` =&gt; `~0`, `\/` =&gt; `~1`\n\n### `source: &quot;exec&quot;`\n\n```json5  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\n{ source: &quot;exec&quot;, provider: &quot;vault&quot;, id: &quot;providers\/openai\/apiKey&quot; }\n<\/code><\/pre>\n<p>Validation:<\/p>\n<ul>\n<li><code>provider<\/code> must match <code>^[a-z][a-z0-9_-]{0,63}$<\/code><\/li>\n<li><code>id<\/code> must match <code>^[A-Za-z0-9][A-Za-z0-9._:\/-]{0,255}$<\/code><\/li>\n<li><code>id<\/code> must not contain <code>.<\/code> or <code>..<\/code> as slash-delimited path segments (for example <code>a\/..\/b<\/code> is rejected)<\/li>\n<\/ul>\n<h2>Provider config<\/h2>\n<p>Define providers under <code>secrets.providers<\/code>:<\/p>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  secrets: {<br \/>\n    providers: {<br \/>\n      default: { source: &#8220;env&#8221; },<br \/>\n      filemain: {<br \/>\n        source: &#8220;file&#8221;,<br \/>\n        path: &#8220;~\/.openclaw\/secrets.json&#8221;,<br \/>\n        mode: &#8220;json&#8221;, \/\/ or &#8220;singleValue&#8221;<br \/>\n      },<br \/>\n      vault: {<br \/>\n        source: &#8220;exec&#8221;,<br \/>\n        command: &#8220;\/usr\/local\/bin\/openclaw-vault-resolver&#8221;,<br \/>\n        args: [&#8220;&#8211;profile&#8221;, &#8220;prod&#8221;],<br \/>\n        passEnv: [&#8220;PATH&#8221;, &#8220;VAULT_ADDR&#8221;],<br \/>\n        jsonOnly: true,<br \/>\n      },<br \/>\n    },<br \/>\n    defaults: {<br \/>\n      env: &#8220;default&#8221;,<br \/>\n      file: &#8220;filemain&#8221;,<br \/>\n      exec: &#8220;vault&#8221;,<br \/>\n    },<br \/>\n    resolution: {<br \/>\n      maxProviderConcurrency: 4,<br \/>\n      maxRefsPerProvider: 512,<br \/>\n      maxBatchBytes: 262144,<br \/>\n    },<br \/>\n  },<br \/>\n}<\/p>\n<pre><code>\n### Env provider\n\n* Optional allowlist via `allowlist`.\n* Missing\/empty env values fail resolution.\n\n### File provider\n\n* Reads local file from `path`.\n* `mode: &quot;json&quot;` expects JSON object payload and resolves `id` as pointer.\n* `mode: &quot;singleValue&quot;` expects ref id `&quot;value&quot;` and returns file contents.\n* Path must pass ownership\/permission checks.\n* Windows fail-closed note: if ACL verification is unavailable for a path, resolution fails. For trusted paths only, set `allowInsecurePath: true` on that provider to bypass path security checks.\n\n### Exec provider\n\n* Runs configured absolute binary path, no shell.\n* By default, `command` must point to a regular file (not a symlink).\n* Set `allowSymlinkCommand: true` to allow symlink command paths (for example Homebrew shims). OpenClaw validates the resolved target path.\n* Pair `allowSymlinkCommand` with `trustedDirs` for package-manager paths (for example `[&quot;\/opt\/homebrew&quot;]`).\n* Supports timeout, no-output timeout, output byte limits, env allowlist, and trusted dirs.\n* Windows fail-closed note: if ACL verification is unavailable for the command path, resolution fails. For trusted paths only, set `allowInsecurePath: true` on that provider to bypass path security checks.\n\nRequest payload (stdin):\n\n```json  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\n{ &quot;protocolVersion&quot;: 1, &quot;provider&quot;: &quot;vault&quot;, &quot;ids&quot;: [&quot;providers\/openai\/apiKey&quot;] }\n<\/code><\/pre>\n<p>Response payload (stdout):<\/p>\n<p>&#8220;`jsonc  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{ &#8220;protocolVersion&#8221;: 1, &#8220;values&#8221;: { &#8220;providers\/openai\/apiKey&#8221;: &#8220;&#8221; } } \/\/ pragma: allowlist secret<\/p>\n<pre><code>\nOptional per-id errors:\n\n```json  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\n{\n  &quot;protocolVersion&quot;: 1,\n  &quot;values&quot;: {},\n  &quot;errors&quot;: { &quot;providers\/openai\/apiKey&quot;: { &quot;message&quot;: &quot;not found&quot; } }\n}\n<\/code><\/pre>\n<h2>Exec integration examples<\/h2>\n<h3>1Password CLI<\/h3>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  secrets: {<br \/>\n    providers: {<br \/>\n      onepassword_openai: {<br \/>\n        source: &#8220;exec&#8221;,<br \/>\n        command: &#8220;\/opt\/homebrew\/bin\/op&#8221;,<br \/>\n        allowSymlinkCommand: true, \/\/ required for Homebrew symlinked binaries<br \/>\n        trustedDirs: [&#8220;\/opt\/homebrew&#8221;],<br \/>\n        args: [&#8220;read&#8221;, &#8220;op:\/\/Personal\/OpenClaw QA API Key\/password&#8221;],<br \/>\n        passEnv: [&#8220;HOME&#8221;],<br \/>\n        jsonOnly: false,<br \/>\n      },<br \/>\n    },<br \/>\n  },<br \/>\n  models: {<br \/>\n    providers: {<br \/>\n      openai: {<br \/>\n        baseUrl: &#8220;https:\/\/api.openai.com\/v1&#8221;,<br \/>\n        models: [{ id: &#8220;gpt-5&#8221;, name: &#8220;gpt-5&#8221; }],<br \/>\n        apiKey: { source: &#8220;exec&#8221;, provider: &#8220;onepassword_openai&#8221;, id: &#8220;value&#8221; },<br \/>\n      },<br \/>\n    },<br \/>\n  },<br \/>\n}<\/p>\n<pre><code>\n### HashiCorp Vault CLI\n\n```json5  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\n{\n  secrets: {\n    providers: {\n      vault_openai: {\n        source: &quot;exec&quot;,\n        command: &quot;\/opt\/homebrew\/bin\/vault&quot;,\n        allowSymlinkCommand: true, \/\/ required for Homebrew symlinked binaries\n        trustedDirs: [&quot;\/opt\/homebrew&quot;],\n        args: [&quot;kv&quot;, &quot;get&quot;, &quot;-field=OPENAI_API_KEY&quot;, &quot;secret\/openclaw&quot;],\n        passEnv: [&quot;VAULT_ADDR&quot;, &quot;VAULT_TOKEN&quot;],\n        jsonOnly: false,\n      },\n    },\n  },\n  models: {\n    providers: {\n      openai: {\n        baseUrl: &quot;https:\/\/api.openai.com\/v1&quot;,\n        models: [{ id: &quot;gpt-5&quot;, name: &quot;gpt-5&quot; }],\n        apiKey: { source: &quot;exec&quot;, provider: &quot;vault_openai&quot;, id: &quot;value&quot; },\n      },\n    },\n  },\n}\n<\/code><\/pre>\n<h3><code>sops<\/code><\/h3>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  secrets: {<br \/>\n    providers: {<br \/>\n      sops_openai: {<br \/>\n        source: &#8220;exec&#8221;,<br \/>\n        command: &#8220;\/opt\/homebrew\/bin\/sops&#8221;,<br \/>\n        allowSymlinkCommand: true, \/\/ required for Homebrew symlinked binaries<br \/>\n        trustedDirs: [&#8220;\/opt\/homebrew&#8221;],<br \/>\n        args: [&#8220;-d&#8221;, &#8220;&#8211;extract&#8221;, &#8216;[&#8220;providers&#8221;][&#8220;openai&#8221;][&#8220;apiKey&#8221;]&#8217;, &#8220;\/path\/to\/secrets.enc.json&#8221;],<br \/>\n        passEnv: [&#8220;SOPS_AGE_KEY_FILE&#8221;],<br \/>\n        jsonOnly: false,<br \/>\n      },<br \/>\n    },<br \/>\n  },<br \/>\n  models: {<br \/>\n    providers: {<br \/>\n      openai: {<br \/>\n        baseUrl: &#8220;https:\/\/api.openai.com\/v1&#8221;,<br \/>\n        models: [{ id: &#8220;gpt-5&#8221;, name: &#8220;gpt-5&#8221; }],<br \/>\n        apiKey: { source: &#8220;exec&#8221;, provider: &#8220;sops_openai&#8221;, id: &#8220;value&#8221; },<br \/>\n      },<br \/>\n    },<br \/>\n  },<br \/>\n}<\/p>\n<pre><code>\n## Sandbox SSH auth material\n\nThe core `ssh` sandbox backend also supports SecretRefs for SSH auth material:\n\n```json5  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\n{\n  agents: {\n    defaults: {\n      sandbox: {\n        mode: &quot;all&quot;,\n        backend: &quot;ssh&quot;,\n        ssh: {\n          target: &quot;user@gateway-host:22&quot;,\n          identityData: { source: &quot;env&quot;, provider: &quot;default&quot;, id: &quot;SSH_IDENTITY&quot; },\n          certificateData: { source: &quot;env&quot;, provider: &quot;default&quot;, id: &quot;SSH_CERTIFICATE&quot; },\n          knownHostsData: { source: &quot;env&quot;, provider: &quot;default&quot;, id: &quot;SSH_KNOWN_HOSTS&quot; },\n        },\n      },\n    },\n  },\n}\n<\/code><\/pre>\n<p>Runtime behavior:<\/p>\n<ul>\n<li>OpenClaw resolves these refs during sandbox activation, not lazily during each SSH call.<\/li>\n<li>Resolved values are written to temp files with restrictive permissions and used in generated SSH config.<\/li>\n<li>If the effective sandbox backend is not <code>ssh<\/code>, these refs stay inactive and do not block startup.<\/li>\n<\/ul>\n<h2>Supported credential surface<\/h2>\n<p>Canonical supported and unsupported credentials are listed in:<\/p>\n<ul>\n<li><a href=\"https:\/\/pa.yingzhi8.cn\/?p=635\">SecretRef Credential Surface<\/a><\/li>\n<\/ul>\n<p>Runtime-minted or rotating credentials and OAuth refresh material are intentionally excluded from read-only SecretRef resolution.<\/p>\n<h2>Required behavior and precedence<\/h2>\n<ul>\n<li>Field without a ref: unchanged.<\/li>\n<li>Field with a ref: required on active surfaces during activation.<\/li>\n<li>If both plaintext and ref are present, ref takes precedence on supported precedence paths.<\/li>\n<\/ul>\n<p>\u8b66\u544a and audit signals:<\/p>\n<ul>\n<li><code>SECRETS_REF_OVERRIDES_PLAINTEXT<\/code> (runtime warning)<\/li>\n<li><code>REF_SHADOWED<\/code> (audit finding when <code>auth-profiles.json<\/code> credentials take precedence over <code>openclaw.json<\/code> refs)<\/li>\n<\/ul>\n<p>Google Chat compatibility behavior:<\/p>\n<ul>\n<li><code>serviceAccountRef<\/code> takes precedence over plaintext <code>serviceAccount<\/code>.<\/li>\n<li>Plaintext value is ignored when sibling ref is set.<\/li>\n<\/ul>\n<h2>Activation triggers<\/h2>\n<p>Secret activation runs on:<\/p>\n<ul>\n<li>Startup (preflight plus final activation)<\/li>\n<li>Config reload hot-apply path<\/li>\n<li>Config reload restart-check path<\/li>\n<li>Manual reload via <code>secrets.reload<\/code><\/li>\n<\/ul>\n<p>Activation contract:<\/p>\n<ul>\n<li>Success swaps the snapshot atomically.<\/li>\n<li>Startup failure aborts \u7f51\u5173 startup.<\/li>\n<li>Runtime reload failure keeps the last-known-good snapshot.<\/li>\n<li>Providing an explicit per-call \u6e20\u9053 token to an outbound helper\/tool call does not trigger SecretRef activation; activation points remain startup, reload, and explicit <code>secrets.reload<\/code>.<\/li>\n<\/ul>\n<h2>Degraded and recovered signals<\/h2>\n<p>When reload-time activation fails after a healthy state, OpenClaw enters degraded secrets state.<\/p>\n<p>One-shot system event and log codes:<\/p>\n<ul>\n<li><code>SECRETS_RELOADER_DEGRADED<\/code><\/li>\n<li><code>SECRETS_RELOADER_RECOVERED<\/code><\/li>\n<\/ul>\n<p>Behavior:<\/p>\n<ul>\n<li>Degraded: runtime keeps last-known-good snapshot.<\/li>\n<li>Recovered: emitted once after the next successful activation.<\/li>\n<li>Repeated failures while already degraded log warnings but do not spam events.<\/li>\n<li>Startup fail-fast does not emit degraded events because runtime never became active.<\/li>\n<\/ul>\n<h2>Command-path resolution<\/h2>\n<p>Command paths can opt into supported SecretRef resolution via \u7f51\u5173 snapshot RPC.<\/p>\n<p>There are two broad behaviors:<\/p>\n<ul>\n<li>Strict command paths (for example <code>openclaw memory<\/code> remote-memory paths and <code>openclaw qr --remote<\/code>) read from the active snapshot and fail fast when a required SecretRef is unavailable.<\/li>\n<li>Read-only command paths (for example <code>openclaw status<\/code>, <code>openclaw status --all<\/code>, <code>openclaw channels status<\/code>, <code>openclaw channels resolve<\/code>, <code>openclaw security audit<\/code>, and read-only doctor\/config repair flows) also prefer the active snapshot, but degrade instead of aborting when a targeted SecretRef is unavailable in that command path.<\/li>\n<\/ul>\n<p>Read-only behavior:<\/p>\n<ul>\n<li>When the \u7f51\u5173 is running, these commands read from the active snapshot first.<\/li>\n<li>If \u7f51\u5173 resolution is incomplete or the \u7f51\u5173 is unavailable, they attempt targeted local fallback for the specific command surface.<\/li>\n<li>If a targeted SecretRef is still unavailable, the command continues with degraded read-only output and explicit diagnostics such as \u201cconfigured but unavailable in this command path\u201d.<\/li>\n<li>This degraded behavior is command-local only. It does not weaken runtime startup, reload, or send\/auth paths.<\/li>\n<\/ul>\n<p>Other notes:<\/p>\n<ul>\n<li>Snapshot refresh after backend secret rotation is handled by <code>openclaw secrets reload<\/code>.<\/li>\n<li>Gateway \u7f51\u5173 RPC method used by these command paths: <code>secrets.resolve<\/code>.<\/li>\n<\/ul>\n<h2>Audit and configure workflow<\/h2>\n<p>Default operator flow:<\/p>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\nopenclaw secrets audit &#8211;check<br \/>\nopenclaw secrets configure<br \/>\nopenclaw secrets audit &#8211;check<\/p>\n<pre><code>\n### `secrets audit`\n\nFindings include:\n\n* plaintext values at rest (`openclaw.json`, `auth-profiles.json`, `.env`, and generated `agents\/*\/agent\/models.json`)\n* plaintext sensitive provider header residues in generated `models.json` entries\n* unresolved refs\n* precedence shadowing (`auth-profiles.json` taking priority over `openclaw.json` refs)\n* legacy residues (`auth.json`, OAuth reminders)\n\nExec note:\n\n* By default, audit skips exec SecretRef resolvability checks to avoid command side effects.\n* Use `openclaw secrets audit --allow-exec` to execute exec providers during audit.\n\nHeader residue note:\n\n* Sensitive provider header detection is name-heuristic based (common auth\/credential header names and fragments such as `authorization`, `x-api-key`, `token`, `secret`, `password`, and `credential`).\n\n### `secrets configure`\n\nInteractive helper that:\n\n* configures `secrets.providers` first (`env`\/`file`\/`exec`, add\/edit\/remove)\n* lets you select supported secret-bearing fields in `openclaw.json` plus `auth-profiles.json` for one agent scope\n* can create a new `auth-profiles.json` mapping directly in the target picker\n* captures SecretRef details (`source`, `provider`, `id`)\n* runs preflight resolution\n* can apply immediately\n\nExec note:\n\n* Preflight skips exec SecretRef checks unless `--allow-exec` is set.\n* If you apply directly from `configure --apply` and the plan includes exec refs\/providers, keep `--allow-exec` set for the apply step too.\n\nHelpful modes:\n\n* `openclaw secrets configure --providers-only`\n* `openclaw secrets configure --skip-provider-setup`\n* `openclaw secrets configure --agent &lt;id&gt;`\n\n`configure` apply defaults:\n\n* scrub matching static credentials from `auth-profiles.json` for targeted providers\n* scrub legacy static `api_key` entries from `auth.json`\n* scrub matching known secret lines from `&lt;config-dir&gt;\/.env`\n\n### `secrets apply`\n\nApply a saved plan:\n\n```bash  theme={&quot;theme&quot;:{&quot;light&quot;:&quot;min-light&quot;,&quot;dark&quot;:&quot;min-dark&quot;}}\nopenclaw secrets apply --from \/tmp\/openclaw-secrets-plan.json\nopenclaw secrets apply --from \/tmp\/openclaw-secrets-plan.json --allow-exec\nopenclaw secrets apply --from \/tmp\/openclaw-secrets-plan.json --dry-run\nopenclaw secrets apply --from \/tmp\/openclaw-secrets-plan.json --dry-run --allow-exec\n<\/code><\/pre>\n<p>Exec note:<\/p>\n<ul>\n<li>dry-run skips exec checks unless <code>--allow-exec<\/code> is set.<\/li>\n<li>write mode rejects plans containing exec SecretRefs\/providers unless <code>--allow-exec<\/code> is set.<\/li>\n<\/ul>\n<p>For strict target\/path contract details and exact rejection rules, see:<\/p>\n<ul>\n<li><a href=\"https:\/\/pa.yingzhi8.cn\/?p=612\">Secrets Apply Plan Contract<\/a><\/li>\n<\/ul>\n<h2>One-way safety policy<\/h2>\n<p>OpenClaw intentionally does not write rollback backups containing historical plaintext secret values.<\/p>\n<p>Safety model:<\/p>\n<ul>\n<li>preflight must succeed before write mode<\/li>\n<li>runtime activation is validated before commit<\/li>\n<li>apply updates files using atomic file replacement and best-effort restore on failure<\/li>\n<\/ul>\n<h2>Legacy auth compatibility notes<\/h2>\n<p>For static credentials, runtime no longer depends on plaintext legacy auth storage.<\/p>\n<ul>\n<li>Runtime credential source is the resolved in-memory snapshot.<\/li>\n<li>Legacy static <code>api_key<\/code> entries are scrubbed when discovered.<\/li>\n<li>OAuth-related compatibility behavior remains separate.<\/li>\n<\/ul>\n<h2>Web UI note<\/h2>\n<p>Some SecretInput unions are easier to configure in raw editor mode than in form mode.<\/p>\n<h2>Related docs<\/h2>\n<ul>\n<li>CLI commands: <a href=\"https:\/\/pa.yingzhi8.cn\/?p=607\">secrets<\/a><\/li>\n<li>Plan contract details: <a href=\"https:\/\/pa.yingzhi8.cn\/?p=612\">Secrets Apply Plan Contract<\/a><\/li>\n<li>Credential surface: <a href=\"https:\/\/pa.yingzhi8.cn\/?p=635\">SecretRef Credential Surface<\/a><\/li>\n<li>Auth setup: <a href=\"https:\/\/pa.yingzhi8.cn\/?p=115\">Authentication<\/a><\/li>\n<li>Security posture: <a href=\"https:\/\/pa.yingzhi8.cn\/?p=747\">Security<\/a><\/li>\n<li>Environment precedence: <a href=\"https:\/\/pa.yingzhi8.cn\/?p=146\">Environment Variables<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Secrets Management Secrets management OpenClaw supports [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-611","post","type-post","status-publish","format-standard","hentry","category-docs"],"_links":{"self":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/611","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/comments?post=611"}],"version-history":[{"count":3,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/611\/revisions"}],"predecessor-version":[{"id":812,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/611\/revisions\/812"}],"wp:attachment":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/media?parent=611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/categories?post=611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/tags?post=611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}