fix(secrets): prevent unresolved SecretRef from crashing embedded agent runs#53577
fix(secrets): prevent unresolved SecretRef from crashing embedded agent runs#53577obviyus merged 2 commits intoopenclaw:mainfrom
Conversation
e806462 to
2fb515f
Compare
Greptile SummaryThis PR fixes a crash in The fix introduces a Key changes:
Confidence Score: 5/5
Reviews (4): Last reviewed commit: "fix(secrets): prevent unresolved SecretR..." | Re-trigger Greptile |
2fb515f to
abb1863
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2fb515f7ef
ℹ️ 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".
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
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". |
abb1863 to
51b5d18
Compare
|
@greptile review |
51b5d18 to
6cd84f1
Compare
|
@greptile review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cd84f104f
ℹ️ 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".
6cd84f1 to
5008781
Compare
5008781 to
1749ee7
Compare
|
Reworked this to fix the contract, not patch stale configs in The real issue was that For this PR, MSTeams now passes only its sender-timezone patch as |
…nt runs Root cause: Telegram channel monitor captures config at startup before secrets are resolved and passes it as configOverride into the reply pipeline. Since getReplyFromConfig() uses configOverride directly (skipping loadConfig() which reads the resolved runtime snapshot), the unresolved SecretRef objects propagate into FollowupRun.run.config and crash runEmbeddedPiAgent(). Fix (defense in depth): - get-reply.ts: detect unresolved SecretRefs in configOverride and fall back to loadConfig() which returns the resolved runtime snapshot - message-tool.ts: try-catch around schema/description building at tool creation time so channel discovery errors don't crash the agent - message-tool.ts: detect unresolved SecretRefs in pre-bound config at tool execution time and fall back to gateway secret resolution Fixes: openclaw#45838
1749ee7 to
753531b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 753531b7db
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| senderTimezone && !cfg.agents?.defaults?.userTimezone | ||
| ? { | ||
| ...cfg, | ||
| agents: { | ||
| ...cfg.agents, | ||
| defaults: { ...cfg.agents?.defaults, userTimezone: senderTimezone }, | ||
| }, |
There was a problem hiding this comment.
Avoid copying stale agent defaults into Teams configOverride
createMSTeamsMessageHandler captures cfg once at startup, but this override now gets merged onto a fresh loadConfig() result in getReplyFromConfig; spreading cfg.agents?.defaults here re-applies the startup snapshot’s entire defaults object on every turn with senderTimezone. That means runtime config updates (for example agents.defaults.model, timeout, or other defaults changed without restart) are silently overwritten for those messages, so Teams can keep using outdated agent defaults even though the new dispatch path is intended to use fresh config.
Useful? React with 👍 / 👎.
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
Vulnerabilities1. 🔵 Tenant/instance config bypass: dispatchReplyFromConfig no longer passes resolved cfg into getReplyFromConfig
Description
As a result, This is a security risk in deployments where
Vulnerable code (new behavior): // dispatch-from-config.ts
const replyResult = await replyResolver(
ctx,
{ /* opts */ },
params.configOverride, // now undefined when no override
);
// get-reply.ts
const cfg =
configOverride == null
? loadConfig() // reloads instead of using the already-resolved cfg
: applyMergePatch(loadConfig(), configOverride);RecommendationEnsure the reply resolver uses the same configuration object that Option A (restore previous safe behavior): await replyResolver(ctx, opts, params.configOverride ?? cfg);Option B (change resolver API to accept
This prevents configuration confusion and ensures tenant/account scoping and validation performed upstream cannot be bypassed by a fresh global config reload. Analyzed PR: #53577 at commit Last updated on: 2026-03-24T16:14:54Z |
Before
After
Summary
When channel monitors (Telegram, Slack, Discord) start, they capture a config snapshot via
loadConfig(). If this happens before the secrets runtime snapshot is activated, the captured config still contains rawSecretRefobjects (e.g.{source: "exec", provider: "doppler", id: "TG_PERSONAL_BOT_TOKEN"}).This captured config is then passed as
configOverridethrough the dispatch chain intogetReplyFromConfig(), which uses it directly — skipping the snapshot-awareloadConfig()that would return resolved secrets. The stale config propagates intoFollowupRun.run.configand eventually crashesrunEmbeddedPiAgent()with:This affects all channels using
exec:,env:, orfile:SecretRef providers for bot tokens.Root cause
The dispatch chain from channel monitor to embedded agent:
server-channels.ts:const cfg = loadConfig()at startup (before secrets resolved)cfgin long-lived closurebot-message-dispatch.ts: passes stalecfgasconfigOverrideget-reply.ts:108:const cfg = configOverride ?? loadConfig()— sinceconfigOverrideexists,loadConfig()is never calledget-reply-run.ts: stores inFollowupRun.run.configrunEmbeddedPiAgent()receives unresolved config — crashFix
Add
hasUnresolvedChannelSecrets()check ingetReplyFromConfig(). WhenconfigOverridecontains unresolvedSecretRefobjects in channel token fields, discard it and fall back toloadConfig()which returns the resolved runtime snapshot.Test plan
/newand/resetcommands no longer crash with SecretRef errorpnpm lintcleanpnpm checkclean (no new type errors)exec:dopplerSecretRef for Telegram bot tokenRelated issues
Codebase search
server-channels.ts->channel.ts->bot-message-dispatch.ts->dispatch-from-config.ts->get-reply.ts->get-reply-run.ts->runEmbeddedPiAgentruntimeConfigSnapshotis set correctly but bypassed viaconfigOverridelobster-biscuit
Sign-Off
AI-assisted: Claude Opus 4 + GPT-5.4 (via OpenClaw). Fully tested on real setup. The author understands the code and the fix.