SecretRef: harden custom/provider secret persistence and reuse#42554
SecretRef: harden custom/provider secret persistence and reuse#42554
Conversation
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟠 models.json env-var marker allows exfiltration of host environment tokens to arbitrary provider baseUrl (confused deputy)
DescriptionThe new If an attacker can influence
The protection is only an allowlist ( Vulnerable code: if (!isKnownEnvApiKeyMarker(customKey)) {
return null;
}
const envValue = normalizeOptionalSecretInput((params.env ?? process.env)[customKey]);
...
return { apiKey: envValue, ... };RecommendationDo not allow Mitigations (pick one or combine):
// models.json
// apiKey: "env:OPENAI_API_KEY"
function parseEnvMarker(value: string): string | null {
const trimmed = value.trim();
if (!trimmed.startsWith("env:")) return null;
return trimmed.slice("env:".length).trim();
}
These changes prevent a config-only attacker from turning an existing environment secret into an outbound credential for an attacker-controlled endpoint. Analyzed PR: #42554 at commit Last updated on: 2026-03-11T00:20:25Z |
Greptile SummaryThis PR hardens SecretRef handling across custom/provider model credentials by centralising "usable credential" vs. "configured marker" semantics, projecting runtime configs onto the source snapshot before writes, preventing stale plaintext preservation during merges, stripping SecretRef marker headers before runtime use, and extending audit scan coverage to env-var-overridden agent directories. The changes are well-structured and backed by comprehensive test coverage. Key changes and observations:
Confidence Score: 4/5
Last reviewed commit: bb04ed0 |
|
Addressed from the Aisle feedback:
For item 1 (custom-provider env marker exfil path): I did not change marker resolution behavior in this PR. That path currently relies on trusted-operator config semantics and existing compatibility (custom endpoints/proxies that intentionally use env markers). Tightening it here would break existing valid configs and is broader than this regression-hardening scope. |
703b91c to
d6520b2
Compare
|
Landed via temp rebase onto main. Thanks @joshavant! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6520b20c5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const stats = fs.statSync(filePath); | ||
| if (options.requireRegularFile && !stats.isFile()) { |
There was a problem hiding this comment.
Use lstat for requireRegularFile checks
When requireRegularFile is enabled, this guard uses fs.statSync, which follows symlinks. A symlinked models.json can therefore satisfy stats.isFile() and still be read, even though the caller explicitly asked to reject non-regular files. In writable state/agent directories this bypasses the hardening added in this commit and can make the audit scan arbitrary link targets; use lstatSync (or an O_NOFOLLOW open) for this check.
Useful? React with 👍 / 👎.
* Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
- Diamond-merge variant of PR openclaw#42554 (fbc6632 = 36d2ae2 variant) - SecretRef custom/provider secret persistence hardening: resolveUsableCustomProviderApiKey(), shouldPreserveExistingApiKey(), readJsonObjectIfExists() size/type guards (5MB cap + requireRegularFile), projectConfigOntoRuntimeSourceSnapshot() shape guard, sanitizeModelHeaders() marker stripping, active agent dir scanning - Audit 1 Claims 1+5 partial + 3 new defense-in-depth controls; 3 gaps unchanged
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant) (cherry picked from commit 36d2ae2)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant) (cherry picked from commit 36d2ae2)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant) (cherry picked from commit fbc6632)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant) (cherry picked from commit fbc6632)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant) (cherry picked from commit fbc6632) # Conflicts: # CHANGELOG.md # extensions/googlechat/src/onboarding.ts # extensions/nextcloud-talk/src/onboarding.ts # src/agents/model-auth-label.test.ts # src/agents/model-auth-label.ts # src/agents/model-auth-markers.test.ts # src/agents/model-auth-markers.ts # src/agents/model-auth.test.ts # src/agents/model-auth.ts # src/agents/models-config.fills-missing-provider-apikey-from-env-var.test.ts # src/agents/models-config.merge.test.ts # src/agents/models-config.merge.ts # src/agents/models-config.providers.normalize-keys.test.ts # src/agents/models-config.providers.ts # src/agents/models-config.runtime-source-snapshot.test.ts # src/agents/models-config.ts # src/agents/pi-embedded-runner/model.test.ts # src/agents/pi-embedded-runner/model.ts # src/auto-reply/reply/directive-handling.auth.test.ts # src/auto-reply/reply/directive-handling.auth.ts # src/commands/auth-choice.model-check.ts # src/commands/model-picker.test.ts # src/commands/model-picker.ts # src/commands/models.list.e2e.test.ts # src/commands/models/list.auth-overview.test.ts # src/commands/models/list.auth-overview.ts # src/commands/models/list.probe.ts # src/commands/models/list.registry.ts # src/commands/models/list.status.test.ts # src/config/config.ts # src/config/io.runtime-snapshot-write.test.ts # src/config/io.ts # src/infra/provider-usage.auth.ts # src/secrets/audit.test.ts # src/secrets/audit.ts # src/secrets/storage-scan.ts
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant) (cherry picked from commit fbc6632) # Conflicts: # src/agents/model-auth-label.test.ts # src/agents/model-auth-label.ts # src/agents/model-auth-markers.test.ts # src/agents/model-auth-markers.ts # src/agents/model-auth.test.ts # src/agents/models-config.fills-missing-provider-apikey-from-env-var.test.ts # src/agents/models-config.merge.test.ts # src/agents/models-config.merge.ts # src/agents/models-config.providers.normalize-keys.test.ts # src/agents/models-config.providers.ts # src/agents/models-config.runtime-source-snapshot.test.ts # src/agents/models-config.ts # src/agents/pi-embedded-runner/model.test.ts # src/agents/pi-embedded-runner/model.ts # src/auto-reply/reply/directive-handling.auth.test.ts # src/auto-reply/reply/directive-handling.auth.ts # src/commands/auth-choice.model-check.ts # src/commands/model-picker.ts # src/commands/models.list.e2e.test.ts # src/commands/models/list.auth-overview.test.ts # src/commands/models/list.auth-overview.ts # src/commands/models/list.probe.ts # src/commands/models/list.registry.ts # src/commands/models/list.status.test.ts # src/config/io.runtime-snapshot-write.test.ts # src/secrets/audit.test.ts # src/secrets/audit.ts # src/secrets/storage-scan.ts
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
…law#42554) * Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (openclaw#42554) (thanks @joshavant)
Summary
This PR hardens SecretRef handling for custom/provider model credentials so secrets are not persisted or reused unsafely across runtime, models.json generation, merge behavior, and audit scans.
It preserves the project goals of:
Problem Surface Addressed
This directly addresses the cluster: custom/provider secrets are persisted or reused unsafely (plaintext or marker leakage).
Main risks covered:
What Changed
1) Usable custom-key semantics centralized and propagated
configured markervsusable secretbehavior.2) Runtime-to-source snapshot projection for models.json writes
3) Merge/provenance hardening for provider apiKey preservation
existing.apiKeywhen the next entry is marker-managed.4) Runtime marker firewall for headers
secretref-managed/secretref-env:*) in inline/provider/fallback model header resolution paths before runtime use.5) Audit coverage hardening
OPENCLAW_AGENT_DIR/PI_CODING_AGENT_DIRoverride paths.Validation
pnpm testpassed (886test files,7241passed,2skipped).pnpm buildandpnpm checkpassed.fails fast at startup when selected web search provider ref is unresolvedkeeps last-known-good runtime snapshot active when refresh fails after a writekeeps last-known-good web runtime snapshot when reload introduces unresolved active web refsLinked Issues / PRs
Fixes #39823
Fixes #42355
Related prior work and superseded proposals: