Skip to content

Commit 8e20dd2

Browse files
authored
Secrets: harden SecretRef-safe models.json persistence (openclaw#38955)
1 parent b08337b commit 8e20dd2

File tree

66 files changed

+2707
-293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2707
-293
lines changed

.secrets.baseline

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9777,35 +9777,35 @@
97779777
"filename": "docs/gateway/configuration-reference.md",
97789778
"hashed_secret": "ec3810e10fb78db55ce38b9c18d1c3eb1db739e0",
97799779
"is_verified": false,
9780-
"line_number": 2039
9780+
"line_number": 2041
97819781
},
97829782
{
97839783
"type": "Secret Keyword",
97849784
"filename": "docs/gateway/configuration-reference.md",
97859785
"hashed_secret": "c1e6ee547fd492df1441ac492e8bb294974712bd",
97869786
"is_verified": false,
9787-
"line_number": 2271
9787+
"line_number": 2273
97889788
},
97899789
{
97909790
"type": "Secret Keyword",
97919791
"filename": "docs/gateway/configuration-reference.md",
97929792
"hashed_secret": "45d676e7c6ab44cf4b8fa366ef2d8fccd3e6d6e6",
97939793
"is_verified": false,
9794-
"line_number": 2399
9794+
"line_number": 2401
97959795
},
97969796
{
97979797
"type": "Secret Keyword",
97989798
"filename": "docs/gateway/configuration-reference.md",
97999799
"hashed_secret": "a219d7693c25cd2d93313512e200ff3eb374d281",
98009800
"is_verified": false,
9801-
"line_number": 2652
9801+
"line_number": 2654
98029802
},
98039803
{
98049804
"type": "Secret Keyword",
98059805
"filename": "docs/gateway/configuration-reference.md",
98069806
"hashed_secret": "b6f56e5e92078ed7c078c46fbfeedcbe5719bc25",
98079807
"is_verified": false,
9808-
"line_number": 2654
9808+
"line_number": 2656
98099809
}
98109810
],
98119811
"docs/gateway/configuration.md": [
@@ -14725,5 +14725,5 @@
1472514725
}
1472614726
]
1472714727
},
14728-
"generated_at": "2026-03-07T11:12:54Z"
14728+
"generated_at": "2026-03-07T16:49:39Z"
1472914729
}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ Docs: https://docs.openclaw.ai
110110
- TUI/session-key canonicalization: normalize `openclaw tui --session` values to lowercase so uppercase session names no longer drop real-time streaming updates due to gateway/TUI key mismatches. (#33866, #34013) thanks @lynnzc.
111111
- iMessage/echo loop hardening: strip leaked assistant-internal scaffolding from outbound iMessage replies, drop reflected assistant-content messages before they re-enter inbound processing, extend echo-cache text retention for delayed reflections, and suppress repeated loop traffic before it amplifies into queue overflow. (#33295) Thanks @joelnishanth.
112112
- Outbound/send config threading: pass resolved SecretRef config through outbound adapters and helper send paths so send flows do not reload unresolved runtime config. (#33987) Thanks @joshavant.
113+
- Secrets/models.json persistence hardening: keep SecretRef-managed api keys + headers from persisting in generated models.json, expand audit/apply coverage, and harden marker handling/serialization. (#38955) Thanks @joshavant.
113114
- Sessions/subagent attachments: remove `attachments[].content.maxLength` from `sessions_spawn` schema to avoid llama.cpp GBNF repetition overflow, and preflight UTF-8 byte size before buffer allocation while keeping runtime file-size enforcement unchanged. (#33648) Thanks @anisoptera.
114115
- Runtime/tool-state stability: recover from dangling Anthropic `tool_use` after compaction, serialize long-running Discord handler runs without blocking new inbound events, and prevent stale busy snapshots from suppressing stuck-channel recovery. (from #33630, #33583) Thanks @kevinWangSheng and @theotarr.
115116
- ACP/Discord startup hardening: clean up stuck ACP worker children on gateway restart, unbind stale ACP thread bindings during Discord startup reconciliation, and add per-thread listener watchdog timeouts so wedged turns cannot block later messages. (#33699) Thanks @dutifulbob.

docs/cli/agent.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ openclaw agent --agent ops --message "Summarize logs"
2222
openclaw agent --session-id 1234 --message "Summarize inbox" --thinking medium
2323
openclaw agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports"
2424
```
25+
26+
## Notes
27+
28+
- When this command triggers `models.json` regeneration, SecretRef-managed provider credentials are persisted as non-secret markers (for example env var names or `secretref-managed`), not resolved secret plaintext.

docs/cli/models.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Notes:
3838
- `models set <model-or-alias>` accepts `provider/model` or an alias.
3939
- Model refs are parsed by splitting on the **first** `/`. If the model ID includes `/` (OpenRouter-style), include the provider prefix (example: `openrouter/moonshotai/kimi-k2`).
4040
- If you omit the provider, OpenClaw treats the input as an alias or a model for the **default provider** (only works when there is no `/` in the model ID).
41+
- `models status` may show `marker(<value>)` in auth output for non-secret placeholders (for example `OPENAI_API_KEY`, `secretref-managed`, `minimax-oauth`, `qwen-oauth`, `ollama-local`) instead of masking them as secrets.
4142

4243
### `models status`
4344

docs/cli/secrets.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Use `openclaw secrets` to manage SecretRefs and keep the active runtime snapshot
1414
Command roles:
1515

1616
- `reload`: gateway RPC (`secrets.reload`) that re-resolves refs and swaps runtime snapshot only on full success (no config writes).
17-
- `audit`: read-only scan of configuration/auth stores and legacy residues for plaintext, unresolved refs, and precedence drift.
17+
- `audit`: read-only scan of configuration/auth/generated-model stores and legacy residues for plaintext, unresolved refs, and precedence drift.
1818
- `configure`: interactive planner for provider setup, target mapping, and preflight (TTY required).
1919
- `apply`: execute a saved plan (`--dry-run` for validation only), then scrub targeted plaintext residues.
2020

@@ -62,8 +62,13 @@ Scan OpenClaw state for:
6262
- plaintext secret storage
6363
- unresolved refs
6464
- precedence drift (`auth-profiles.json` credentials shadowing `openclaw.json` refs)
65+
- generated `agents/*/agent/models.json` residues (provider `apiKey` values and sensitive provider headers)
6566
- legacy residues (legacy auth store entries, OAuth reminders)
6667

68+
Header residue note:
69+
70+
- 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`).
71+
6772
```bash
6873
openclaw secrets audit
6974
openclaw secrets audit --check

docs/concepts/models.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ is merged by default unless `models.mode` is set to `replace`.
212212

213213
Merge mode precedence for matching provider IDs:
214214

215-
- Non-empty `apiKey`/`baseUrl` already present in the agent `models.json` win.
215+
- Non-empty `baseUrl` already present in the agent `models.json` wins.
216+
- Non-empty `apiKey` in the agent `models.json` wins only when that provider is not SecretRef-managed in current config/auth-profile context.
217+
- SecretRef-managed provider `apiKey` values are refreshed from source markers (`ENV_VAR_NAME` for env refs, `secretref-managed` for file/exec refs) instead of persisting resolved secrets.
216218
- Empty or missing agent `apiKey`/`baseUrl` fall back to config `models.providers`.
217219
- Other provider fields are refreshed from config and normalized catalog data.
220+
221+
This marker-based persistence applies whenever OpenClaw regenerates `models.json`, including command-driven paths like `openclaw agent`.

docs/gateway/configuration-reference.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,9 @@ OpenClaw uses the pi-coding-agent model catalog. Add custom providers via `model
20042004
- Use `authHeader: true` + `headers` for custom auth needs.
20052005
- Override agent config root with `OPENCLAW_AGENT_DIR` (or `PI_CODING_AGENT_DIR`).
20062006
- Merge precedence for matching provider IDs:
2007-
- Non-empty agent `models.json` `apiKey`/`baseUrl` win.
2007+
- Non-empty agent `models.json` `baseUrl` values win.
2008+
- Non-empty agent `apiKey` values win only when that provider is not SecretRef-managed in current config/auth-profile context.
2009+
- SecretRef-managed provider `apiKey` values are refreshed from source markers (`ENV_VAR_NAME` for env refs, `secretref-managed` for file/exec refs) instead of persisting resolved secrets.
20082010
- Empty or missing agent `apiKey`/`baseUrl` fall back to `models.providers` in config.
20092011
- Matching model `contextWindow`/`maxTokens` use the higher value between explicit config and implicit catalog values.
20102012
- Use `models.mode: "replace"` when you want config to fully rewrite `models.json`.

docs/gateway/secrets.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,16 @@ openclaw secrets audit --check
372372

373373
Findings include:
374374

375-
- plaintext values at rest (`openclaw.json`, `auth-profiles.json`, `.env`)
375+
- plaintext values at rest (`openclaw.json`, `auth-profiles.json`, `.env`, and generated `agents/*/agent/models.json`)
376+
- plaintext sensitive provider header residues in generated `models.json` entries
376377
- unresolved refs
377378
- precedence shadowing (`auth-profiles.json` taking priority over `openclaw.json` refs)
378379
- legacy residues (`auth.json`, OAuth reminders)
379380

381+
Header residue note:
382+
383+
- 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`).
384+
380385
### `secrets configure`
381386

382387
Interactive helper that:

docs/reference/secretref-credential-surface.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Scope intent:
2323
[//]: # "secretref-supported-list-start"
2424

2525
- `models.providers.*.apiKey`
26+
- `models.providers.*.headers.*`
2627
- `skills.entries.*.apiKey`
2728
- `agents.defaults.memorySearch.remote.apiKey`
2829
- `agents.list[].memorySearch.remote.apiKey`
@@ -98,6 +99,7 @@ Notes:
9899
- Auth-profile plan targets require `agentId`.
99100
- Plan entries target `profiles.*.key` / `profiles.*.token` and write sibling refs (`keyRef` / `tokenRef`).
100101
- Auth-profile refs are included in runtime resolution and audit coverage.
102+
- For SecretRef-managed model providers, generated `agents/*/agent/models.json` entries persist non-secret markers (not resolved secret values) for `apiKey`/header surfaces.
101103
- For web search:
102104
- In explicit provider mode (`tools.web.search.provider` set), only the selected provider key is active.
103105
- In auto mode (`tools.web.search.provider` unset), `tools.web.search.apiKey` and provider-specific keys are active.

docs/reference/secretref-user-supplied-credentials-matrix.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,13 @@
426426
"secretShape": "secret_input",
427427
"optIn": true
428428
},
429+
{
430+
"id": "models.providers.*.headers.*",
431+
"configFile": "openclaw.json",
432+
"path": "models.providers.*.headers.*",
433+
"secretShape": "secret_input",
434+
"optIn": true
435+
},
429436
{
430437
"id": "skills.entries.*.apiKey",
431438
"configFile": "openclaw.json",

0 commit comments

Comments
 (0)