fix(config): redact sourceConfig and runtimeConfig alias fields in redactConfigSnapshot [AI]#66030
Conversation
Greptile SummaryThis PR fixes a security regression in Confidence Score: 5/5This PR is safe to merge — it is a minimal, correct security fix with no logic changes outside the targeted redaction function. The change is narrowly scoped: two fields added to two return statements, with matching tests that check both sentinel values and reference equality. The type definitions confirm sourceConfig/resolved are the same ResolvedSourceConfig type and runtimeConfig/config are the same RuntimeConfig type, so the aliasing is correct. No other fields in ConfigFileSnapshot are unredacted aliases. No files require special attention. Reviews (1): Last reviewed commit: "fix: address issue" | Re-trigger Greptile |
|
@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". |
* fix(matrix): sync runtime dependency lockfile * fix(matrix): mirror staged runtime dependencies * fix(release): allow matrix runtime pack size * [codex] Fix LM Studio header-auth follow-ups (openclaw#65806) * fix: harden lmstudio header auth handling * fix: suppress lmstudio shell env auth * fix(docker): install bundled plugin deps after prune * fix: extract shared session status runtime (openclaw#65807) Merged via squash. Prepared head SHA: f027bd6 Co-authored-by: dutifulbob <261991368+dutifulbob@users.noreply.github.com> Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com> Reviewed-by: @osolmaz * fix: preserve qmd command paths * fix: harden qmd service startup * test(release): align pack size budget assertion * feat: Streamline Feishu channel onboarding with QR code scan-to-create flow (openclaw#65680) Add QR-based app registration, improve Feishu onboarding flows, support direct login entry, add group chat policy setup, reduce log noise, and update docs. * fix(ci): verify bundled plugin runtime deps * fix(feishu): avoid sdk facade cycles * fix(feishu): keep channel auth on local api barrel * fix(feishu): break auth login barrel cycle * fix(feishu): guard app registration fetches * test: fix macos parallels gateway fallback * ci: add stable npm dist-tag sync * docs: clarify npm dist-tag auth * feat(docs): add Hostinger installation guide and link in VPS document… (openclaw#65904) * Run context-engine turn maintenance as idle-aware background work (openclaw#65233) Merged via squash. Prepared head SHA: e9f6c67 Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman * fix(logging) add failover log source and target (openclaw#65955) * clarify failover log source and target * fix embedded runner final assistant raw text helper * feat(plugin-sdk): add claimable dedupe helper * refactor(line): share replay dedupe guard * refactor(feishu): reuse persistent dedupe lookups * fix(qr): lazy load terminal runtime modules * test(wizard): mock auth profile runtime seam * fix(qr): lazy load terminal ascii renderer * perf(wizard): keep explicit skip auth path cold * refactor(feishu): share synthetic event dedupe claims * perf(daemon): keep install auth env path cold * fix(nextcloud-talk): release replay claims on handler failure * fix(plugin-sdk): serialize claimable dedupe races * fix(plugins): treat context-engine plugins as capabilities in status/inspect (openclaw#58766) Merged via squash. Prepared head SHA: 23269d2 Co-authored-by: zhuisDEV <95547369+zhuisDEV@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman * fix(nextcloud-talk): make replay retries explicit * fix(zalo): make replay retries explicit * fix: validate resolved context engine contracts (openclaw#63222) Merged via squash. Prepared head SHA: 5f3a15c Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman * fix(mattermost): make replay retries explicit * fix(whatsapp): make inbound retries explicit * perf(secrets): fast-path explicit channel target lookup * perf(cli): skip redundant schema passes for structured dry runs * fix(discord): make inbound retries explicit * perf(agents): keep fallback auth store cold without sources * fix(slack): make inbound retries explicit * fix(matrix): make delivery replay retries explicit * fix(line): make webhook replay retries explicit * fix(feishu): make card action retries explicit * fix(whatsapp): await write stream finish before returning encFilePath (openclaw#65896) * fix(whatsapp): await write stream finish in encryptedStream to fix race-condition ENOENT crash * fix(whatsapp): ship Baileys media hotfix on npm installs * fix(whatsapp): keep Baileys hotfix postinstall best-effort * fix(whatsapp): harden Baileys postinstall temp writes * fix(whatsapp): preserve Baileys hotfix file mode --------- Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net> * perf(config): reuse validated best-effort snapshots * perf(infra): cache login shell env probes * fix(gateway): harden service entrypoint resolution (openclaw#65984) Merged via squash. Prepared head SHA: 31cbc33 Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * fix(feishu): make bot menu retries explicit * fix(feishu): keep comment replay closed after generic failures * perf(cron): lazy-load isolated cli runner runtime * fix(plugin-sdk): avoid leaking queue rejection cleanup * fix(tasks): avoid leaking scheduled sweep failures * perf(cron): keep auth profile runtime cold * fix(telegram): swallow update watermark persistence failures * perf(cron): narrow session runtime imports * fix(auto-reply): release inbound dedupe after dispatch errors * fix(auto-reply): avoid leaking inbound debounce cleanup * perf(cron): isolate runtime-heavy seams * fix(telegram): avoid leaking thread binding persist cleanup * perf(cron): lazy-load embedded runtime branch * fix: stop repeated unknown-tool loops (openclaw#65922) Merged via squash. Prepared head SHA: f352a27 Reviewed-by: @osolmaz * fix(runtime): avoid leaking detached cleanup promises * perf(cron): trim unused runtime barrel exports * fix(tlon): release replay claims after handler failures * fix(nostr): retry inbound events after handler failures * perf(cron): narrow live switch error import * perf(agents): keep model fallback auth runtime cold * fix(telegram): block watermark advancement past failed updates * perf(cron): lazy-load context and catalog lookups * perf(cron): use session store read path * perf(cron): lazy-load delivery subagent registry * fix(voice-call): retry rejected inbound hangups * perf(cron): lazy-load skills snapshot runtime * fix(telegram): defer replay commit until update succeeds * fix(voice-call): keep unknown-call replays retryable * perf(outbound): use read-only channel registry seam * perf(outbound): use loaded-only channel plugin reads * fix(telegram): retry failed group migration updates * perf(outbound): isolate id-like target resolution * fix(telegram): retry failed reaction updates * perf(agents): narrow failover helper imports * perf(plugins): isolate manifest registry cache state * perf(auth-profiles): narrow source check path imports * fix(telegram): retry failed model callbacks * fix(heartbeat): preserve Telegram topic routing for isolated heartbeats (openclaw#66035) Merged via squash. Prepared head SHA: 83b986a Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * fix(telegram): retry failed commands pagination callbacks * perf(channels): isolate loaded target parsing * perf(outbound): narrow loaded target channel reads * perf(utils): isolate message channel normalization * fix(telegram): retry failed plugin binding callbacks * perf(cron): lazy-load delivery logger runtime * fix(telegram): retry failed pagination preflight * fix(telegram): retry failed model browser callbacks * perf(channels): read bundled channel metadata directly * perf(cron): use read-only allow-from store seam * fix(mattermost): dedupe repeated model picker selects * fix(browser): unblock managed loopback CDP startup and control (openclaw#66043) Merged via squash. Prepared head SHA: c3d0a99 Reviewed-by: @mbelinky * perf(sessions): use loaded thread-info seam * fix(voice-call): keep retryable errors replayable * perf(cron): narrow execution and skill runtime imports * fix(telegram): retry failed model selections * perf(cron): use narrow bound-account lookup * fix(telegram): retry failed approval callbacks * test(cron): mock skills snapshot runtime seam * fix(plugins): serialize interactive callback dedupe * fix(nostr): dedupe deterministic rejected events * perf(cron): drop stale skill snapshot runtime exports * perf(cron): use lightweight model selection resolver * perf(agents): use lightweight model fallback selection helpers * perf(cron): use narrow verbose-level runtime seam * Gateway/sessions: preserve shared session route on system events (openclaw#66073) Merged via squash. Prepared head SHA: 314a935 Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * perf(channels): split hot-path message channel normalization * perf(sessions): isolate reset policy helpers * perf(cron): lazy-load run executor runtime * perf(cron): lazy-load external content runtime * perf(agents): isolate thinking default helper * fix(browser): detect local attachOnly loopback CDP sessions (openclaw#66080) Merged via squash. Prepared head SHA: 90c1c10 Reviewed-by: @mbelinky * perf(agents): isolate agent scope config helpers * fix(session): clear stale thread route on system events * perf(cron): lazy-load delivery runtime helpers * perf(cron): keep skill filter runtime lazy * fix(bluebubbles): lazy-refresh Private API status on send (openclaw#43764) (openclaw#65447) * fix(bluebubbles): lazy refresh Private API cache on send to prevent silent reply threading degradation (openclaw#43764) When the 10-minute server info cache expires, sends requesting reply threading or effects silently degrade to plain messages. Add a lazy async refresh of the cache in the send path when Private API features are needed but status is unknown, preserving graceful degradation if the refresh fails. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(bluebubbles): apply lazy Private API refresh to attachment sends and add missing test coverage (openclaw#43764) Attachment sends had the same cache-expiry bug as text sends: when the 10-minute Private API status cache TTL expired, reply threading metadata was silently dropped. Apply the same lazy-refresh pattern from send.ts. Also add the missing "refresh succeeds with private_api: false" test case for both send.ts and attachments.ts — proves effects throw and reply threading degrades without the "unknown" warning when the API is explicitly disabled. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update no-raw-channel-fetch allowlist for test-harness line shift Adding fetchBlueBubblesServerInfo to the probe mock module shifted globalThis.fetch in test-harness.ts from line 128 to 130. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Lobster <lobster@shahine.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(telegram): add inbound retry regressions (openclaw#66075) Merged via squash. Prepared head SHA: 175cd25 Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * fix: expose telegram topic names in agent context (openclaw#65973) (thanks @ptahdunbar) * feat(telegram): expose forum topic names in agent context Telegram Bot API does not provide a method to look up forum topic names by thread ID. This adds an in-memory LRU cache that learns topic names from service messages (forum_topic_created, forum_topic_edited, forum_topic_closed, forum_topic_reopened) and seeds from reply_to_message.forum_topic_created as a fallback for pre-existing topics. The resolved topic name is surfaced as: - TopicName in MsgContext (available to {{TopicName}} in templates) - topic_name in the agent prompt metadata block - topicName in plugin hook event metadata Includes unit tests for the topic-name-cache module (11 tests including eviction and read-recency). Known limitation: cache is in-memory only; after a restart it falls back to the creation-time name until a rename event is observed. * refactor(telegram): distill topic name flow * fix: expose telegram topic names in agent context (openclaw#65973) (thanks @ptahdunbar) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * perf(config): skip shell env fallback for explicit empty vars * fix(cron): stop unresolved next-run refire loops (openclaw#66083) Merged via squash. Prepared head SHA: b86ba58 * perf(daemon): lazy-load auth profile install helpers * fix(config): redact sourceConfig and runtimeConfig alias fields in redactConfigSnapshot [AI] (openclaw#66030) * fix: address issue * docs: add changelog entry for PR merge * perf(daemon): slim gateway install token imports * fix(msteams): enforce sender allowlist checks on SSO signin invokes [AI] (openclaw#66033) * fix: address issue * fix: address PR review feedback * docs: add changelog entry for PR merge * perf(daemon): import install config helpers directly * fix(browser): enforce SSRF policy on snapshot, screenshot, and tab routes [AI] (openclaw#66040) * fix: address issue * fix: address review feedback * fix: finalize issue changes * fix: address review-pr skill feedback * fix: address PR review feedback * fix: address PR review feedback * docs: add changelog entry for PR merge * perf(config): reuse prepared snapshots for daemon token writes * perf(config): defer legacy web search registry reads * Lobster: import published core runtime (openclaw#64755) * Lobster: import published core runtime * Changelog: add Lobster core runtime note * Lobster: type embedded core runtime * Lobster: keep package-boundary tsconfig narrow * perf(config): use direct writes for gateway token persistence * fix(heartbeat): force owner downgrade for untrusted hook:wake system events [AI-assisted] (openclaw#66031) * fix: address issue * fix: address PR review feedback * fix: address review-pr skill feedback * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * fix: address PR review feedback * docs: add changelog entry for PR merge * fix(cron): preserve unresolved next-run backoff (openclaw#66113) Merged via squash. Prepared head SHA: a553daa Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * agents: stop strict mode from hijacking chat turns * perf(secrets): lazy-load provider env var exports * fix: classify openrouter json 404 model errors Rewrites the stale branch on top of current `main` and preserves the original issue as regression coverage for the exact OpenRouter JSON 404 payload from openclaw#51571. No production behavior changes are introduced here; current `main` already classifies this payload as `model_not_found`, and this merge locks that in across the shared matcher, failover classifier, and fallback loop. Co-authored-by: 屈定 <mrdear@users.noreply.github.com> Co-authored-by: Altay <altay@uinaf.dev> * test(cron): fix openclaw#66019 maintenance regression coverage (openclaw#66122) Merged via squash. Prepared head SHA: 7f2a604 * perf(config): use generated SecretRef policy metadata * perf(config): skip cold runtime refresh on one-shot writes * fix(trace command): Improve trace raw diagnostics and trace command UX (openclaw#66089) * improve trace raw diagnostics and command acks * address trace review feedback * avoid sync transcript reads in raw trace * preserve raw cli output for trace * gate trace emission at reply time * reflect raw trace mode in status surfaces * fix(outbound): replay queued session context (openclaw#66025) * fix(outbound): preserve replay session context * fix(outbound): remove user work log * changelog: note outbound session-context replay fix (openclaw#66025) --------- Co-authored-by: Devin Robison <drobison@nvidia.com> * fix(queue): split collect batches by auth context (openclaw#66024) * fix(queue): split collect batches by auth context Co-authored-by: zsx <git@zsxsoft.com> * fix(queue): keep overflow summary on splits * fix(queue): preserve grouped collect retry semantics * fix(queue): drop USER.md from pr * fix(queue): keep overflow summary in first auth group * fix(queue): clear overflow summary state after first auth group * fix(queue): narrow auth split key * fix(queue): flush collect summary-only drains * changelog: note collect-mode auth-context batch split (openclaw#66024) --------- Co-authored-by: zsx <git@zsxsoft.com> Co-authored-by: Devin Robison <drobison@nvidia.com> * perf(config): narrow channel legacy rule loading * perf(config): scope dry-run legacy validation * perf(agents): lazy-load cli runner seams * perf(commands): narrow session test imports * fix(memory-core): run Dreaming once per cron schedule (openclaw#66139) Merged via squash. Prepared head SHA: 48229a2 Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * perf(commands): narrow agent config imports * perf(commands): lazy-load agent secret resolution * [codex] fix(ui): guard dreaming wiki plugin calls (openclaw#66140) Merged via squash. Prepared head SHA: 030562b Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com> Reviewed-by: @mbelinky * perf(agents): keep attempt execution runtime cold * perf(agents): lazy-load delivery runtime * perf(agents): lazy-load session store updates * perf(agents): narrow session helper imports * fix: allow plugin commands on Slack when channel supports native commands (openclaw#64578) Merged via squash. Prepared head SHA: 2ec97bf Co-authored-by: rafaelreis-r <57492577+rafaelreis-r@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman * perf(config): keep runtime compat migrations lightweight * fix(ui): preserve user-selected session on reconnect and tab switch (openclaw#59611) thanks @loong0306 Fixes openclaw#57072 — chat UI state desync after route navigation. - applySessionDefaults() now detects user-selected sessions and preserves them on reconnect - Chat tab session switching consolidated to use switchChatSession() helper - Overview session-key handler uses shared resetChatStateForSessionSwitch to prevent stale state leaks - Session select dropdowns now set ?selected to reflect actual state Co-authored-by: loong0306 <loong0306@gmail.com> Co-authored-by: Nova <nova@openknot.ai> * fix: count unknown-tool retries only when streamed (openclaw#66145) Merged via squash. Prepared head SHA: b79209c Co-authored-by: Bob <dutifulbob@gmail.com> Reviewed-by: @osolmaz * fix(active-memory): Move active memory recall into the hidden prompt prefix (openclaw#66144) * move active memory into prompt prefix * document active memory prompt prefix * strip active memory prefixes from recall history * harden active memory prompt prefix handling * hide active memory prefix in leading history views * strip hidden memory blocks after prompt merges * preserve user turns in memory recall cleanup * fix(ui): replace marked.js with markdown-it to fix ReDoS UI freeze (openclaw#46707) thanks @zhangfnf Replace marked.js with markdown-it for the control UI chat markdown renderer to eliminate a ReDoS vulnerability that could freeze the browser tab. - Configure markdown-it with custom renderers matching marked.js output - Add GFM www-autolink with trailing punctuation stripping per spec - Escape raw HTML via html_block/html_inline overrides - Flatten remote images to alt text, preserve base64 data URI images - Add task list support via markdown-it-task-lists plugin - Trim trailing CJK characters from auto-linked URLs (RFC 3986) - Keep marked dependency for agents-panels-status-files.ts usage Co-authored-by: zhangfan49 <zhangfan49@baidu.com> Co-authored-by: Nova <nova@openknot.ai> * fix(ci): unblock discord boundary typing * fix(ci): repair extension boundary contracts * fix(ci): mirror whatsapp runtime dependency * fix(ci): align cron and session tests with runtime * fix(ci): clear residual tsgo blockers * fix(ci): repair baileys lockfile snapshot * fix(memory): unify default root memory handling (openclaw#66141) * fix(memory): unify default root memory handling * test(memory): align legacy migration expectation * docs(changelog): tag qmd root-memory fix * docs(changelog): append qmd root-memory entry * docs(changelog): dedupe qmd root-memory entry * docs(changelog): attribute qmd root-memory fix --------- Co-authored-by: mbelinky <mbelinky@users.noreply.github.com> * fix: normalize OpenAI minimal reasoning * chore: fix pulled lint assertion * plugins: trim staged runtime cargo * fix(ci): restore plugin-local whatsapp deps * fix(ci): align cron tests with default model * fix(ci): repair agent test mocks * fix(ci): repair telegram topic cache typing * fix(ci): repair telegram ui and watch regressions * fix(stream): tighten voice stream ingress guards (openclaw#66027) * fix(stream): tighten voice stream ingress guards * fix(stream): address review follow-ups * fix(stream): normalize trusted proxy ip matching * changelog: note voice-call media-stream ingress guard tightening (openclaw#66027) * fix(stream): require non-empty trusted proxy list before honoring forwarding headers Without an explicit trusted proxy list, the prior gate treated every remote as 'from a trusted proxy', so enabling trustForwardingHeaders let any direct caller spoof X-Forwarded-For / X-Real-IP and rotate the resolved IP per request to evade maxPendingConnectionsPerIp. Require trustedProxyIPs to be non-empty AND match the remote before trusting forwarding headers. --------- Co-authored-by: Devin Robison <drobison@nvidia.com> * Feishu: tighten allowlist target canonicalization (openclaw#66021) * fix(feishu): tighten allowlist id matching * fix(feishu): address review follow-ups * changelog: note Feishu allowlist canonicalization tightening (openclaw#66021) * fix(feishu): collapse typed wildcard allowlist aliases to bare wildcard Previously normalizeFeishuTarget folded chat:* / user:* / open_id:* / dm:* / group:* / channel:* down to '*', so those entries acted as allow-all. The new typed canonicalization was producing literal keys (chat:*, user:*, ...) that never matched any sender, silently flipping those configs from allow-all to deny-all. Restore the prior behavior by collapsing a wildcard value to '*' inside canonicalizeFeishuAllowlistKey. --------- Co-authored-by: Devin Robison <drobison@nvidia.com> * fix(ci): mirror whatsapp runtime dependency * docs(changelog): note perf fixes * test: align failover source model expectation * fix: sendPolicy deny should suppress delivery, not inbound processing (openclaw#53328) (openclaw#65461) * fix: sendPolicy deny suppresses delivery, not inbound processing (openclaw#53328) Previously, sendPolicy "deny" returned early before the agent dispatch, preventing the agent from ever seeing the message. This broke the use case of an agent listening on WhatsApp groups with sendPolicy: deny to read messages without replying — the agent couldn't read them at all. Move the deny gate from before the agent dispatch to after it. The agent now processes inbound messages normally (context, memory, tool calls), but all outbound delivery paths are suppressed: final replies, tool results, block replies, working status, plan updates, typing indicators, and TTS payloads. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: propagate sendPolicy to ACP tail dispatch instead of hardcoded allow The ACP tail dispatch path (ctx.AcpDispatchTailAfterReset) was passing sendPolicy: "allow" unconditionally, which would bypass delivery suppression in a /reset <tail> turn when the session has sendPolicy deny. Pass through the resolved sendPolicy so the tail dispatch respects it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: guard before_dispatch hook and ACP tail dispatch under sendPolicy deny before_dispatch handled replies were leaking through sendFinalPayload before the suppressDelivery guard was checked. ACP tail dispatch (from /new <tail>) was being rejected by acp-runtime.ts deny checks instead of proceeding with delivery suppression handled downstream. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * auto-reply: propagate deny suppression to reply_dispatch * fix(acp): suppress onReplyStart when user delivery is denied When sendPolicy resolves to "deny", ACP tail dispatch still invoked onReplyStart via startReplyLifecycle before the suppressUserDelivery check. Channels wire onReplyStart to typing indicators, so deny-scoped sessions could still emit outbound typing events on /reset <tail> flows and command bypass paths. Gate startReplyLifecycleOnce on suppressUserDelivery so the lifecycle is marked started but the callback is skipped. Payload delivery was already suppressed; this closes the typing-indicator leak flagged by Codex review (PR openclaw#65461 P1/P2). * fix(acp): route non-tail deny turns through ACP when suppression is wired tryDispatchAcpReplyHook was returning early for non-tail, non-command ACP turns under sendPolicy: "deny", causing ACP-bound sessions to fall back to the embedded reply path instead of flowing through acpManager.runTurn. That diverged ACP session state, tool calls, and memory whenever delivery suppression was active. Now the early-return only fires when sendPolicy is "deny" AND the event lacks suppressUserDelivery — i.e., when downstream delivery suppression is not wired up. When suppressUserDelivery is set, dispatch-acp-delivery already drops outbound sends (see onReplyStart / deliver guards), so ACP can safely run the turn with state consistency preserved. Existing behavior preserved: - Command bypass still overrides deny - Tail dispatch still overrides deny - Plain-text deny turns without suppression still short-circuit Addresses Codex bot P1 feedback on openclaw#65461. * fix: gate empty-body typing indicator behind suppressTyping (openclaw#53328) * fix: guard plugin-binding + fast-abort outbound paths under sendPolicy deny The original PR computed suppressDelivery inside the try block, which was after two outbound paths: 1. The plugin-owned binding block (sendBindingNotice calls for unavailable/declined/error outcomes, plus the plugin's own "handled" outcome) ran before the suppressDelivery flag existed, so plugin notices still leaked under deny. 2. The fast-abort path dispatched "Agent was aborted." via routeReplyToOriginating / sendFinalReply before the flag existed. Move resolveSendPolicy() above the plugin-binding block so suppressDelivery covers every outbound path downstream, matching the PR description's claim that "all outbound paths are guarded by the flag." Plugin-bound inbound handling under deny: plugin handlers can emit outbound replies we cannot rewind, so skip the claim hook entirely under deny and fall through to normal (suppressed) agent processing. touchConversationBindingRecord still runs so binding activity stays tracked. Fast-abort under deny: still run the abort and record the completed state, just don't emit the abort reply. Tests: - suppresses the fast-abort reply under sendPolicy deny - delivers the fast-abort reply normally when sendPolicy is allow (regression guard) - skips plugin-bound claim hook under deny and falls through to suppressed agent dispatch Addresses Codex review findings on PR openclaw#65461. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Lobster <lobster@shahine.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tts): allow OpenClaw temp directory paths in reply media normalizer (openclaw#63511) Merged via squash. Prepared head SHA: 0e9a6da Co-authored-by: jetd1 <15795935+jetd1@users.noreply.github.com> Co-authored-by: grp06 <1573959+grp06@users.noreply.github.com> Reviewed-by: @grp06 * docs(changelog): note sendPolicy suppressDelivery + BB Private API cache fixes (openclaw#66220) Two recently-merged fixes that shipped without CHANGELOG entries: - PR openclaw#65461 (sendPolicy deny suppresses delivery, not inbound processing, closes openclaw#53328) — squash 0362f21 - PR openclaw#65447 (BB lazy-refresh Private API on send to prevent reply threading degradation, closes openclaw#43764) — squash 85cfba6 Backfilling under `## Unreleased` > `### Fixes` before the next release cut. Co-authored-by: Lobster <lobster@shahine.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(changelog): add 2026.4.12 dedupe note * fix: recover reasoning-only OpenAI turns (openclaw#66167) * openclaw-11f.1: retry reasoning-only OpenAI turns Regeneration-Prompt: | Patch the embedded runner so a signed reasoning-only assistant turn with no user-visible text is treated as recoverable instead of silently ending the run. Keep the change focused on the active OpenAI GPT-style path, retry the turn with an explicit visible-answer continuation instruction, and fall back to the existing incomplete-turn error handling only after retries are exhausted. Add regression coverage for the helper classification and for the outer run loop retry behavior, and keep unrelated provider behavior unchanged. * openclaw-11f.1: address reasoning-only review feedback Regeneration-Prompt: | Follow up on PR review feedback for the reasoning-only retry patch. Keep the fix narrow: move the retry limit into a named constant alongside the other retry-policy values, document why the limit is 2, and prevent reasoning-only auto-retries after any side effects so the runner falls back to the existing caution path instead of risking duplicate actions. Add regression coverage for the side-effect guard and the named limit behavior. * openclaw-11f.1: drop local pebbles artifacts Regeneration-Prompt: | Remove accidentally committed local pebbles tracker artifacts from the PR branch without changing runtime code. Keep the cleanup limited to deleting the tracked .pebbles files from version control, and rely on local git excludes for future pebbles activity so these files stay out of diffs. * openclaw-11f.1: tighten reasoning-only retry guards Regeneration-Prompt: | Follow up on the remaining review feedback for the reasoning-only retry path. Keep the fix narrow: do not auto-retry a reasoning-only turn when the assistant already terminated with stopReason error, and evaluate the OpenAI-specific retry guard against the provider/model metadata of the assistant turn that actually produced the partial output rather than the outer run configuration. Add regression coverage for both behaviors in the incomplete-turn runner tests. * openclaw-11f.1: retry empty GPT turns once Regeneration-Prompt: | Extend the embedded runner's GPT-style incomplete-turn recovery with a separate generic empty-response retry path. Keep it narrower than the existing reasoning-only recovery: one retry only, replay-safe only, no side effects, no assistant error turns, and scoped to the active assistant provider/model metadata. Add explicit warning logs when the empty-response retry triggers and when its single retry budget is exhausted, and add regression coverage for the success and exhaustion cases without changing broader provider fallback behavior. * openclaw-11f.1: harden reasoning-only retry completion checks Regeneration-Prompt: | Follow up on the remaining review feedback for the GPT-style recovery path. Keep the change narrow: only retry reasoning-only turns when there is no visible assistant answer yet, and if the reasoning-only retry budget is exhausted without any visible answer, surface the existing incomplete-turn error instead of treating reasoning-only payloads as a successful completion. Add focused regression coverage for both scenarios and preserve the adjacent empty-response retry behavior. * openclaw-11f.1: preserve profile cooldown on retry exhaustion Regeneration-Prompt: | Follow up on the final review comment for the GPT-style recovery path. Keep the change narrow: when the reasoning-only retry budget is exhausted and the run returns the incomplete-turn error early, preserve the same auth-profile cooldown behavior that the normal incomplete-turn branch already applies so multi-profile failover continues to work consistently. Verify the touched runner suites still pass. * fix: recover GPT-style empty turns Regeneration-Prompt: | Add the required changelog entry for the PR that hardens embedded GPT-style recovery of reasoning-only and empty-response turns. Keep the changelog update under ## Unreleased > ### Fixes, append-only, and include the PR number plus author attribution on the same line. * test: launch macos parallels gateway in guest * docs(changelog): tidy unreleased entries * fix(outbound): suppress relay status placeholder leaks * fix(ci): avoid frozen hook test clock hangs * fix(slack): isolate doctor contract API (openclaw#63192) * Slack: isolate doctor contract API * chore: changelog * fix(slack): move doctor changelog entry to Unreleased * Plugins: lock Slack doctor sidecar metadata * Slack: fix changelog entry placement --------- Co-authored-by: @zimeg <zim@o526.net> Co-authored-by: George Pickett <gpickett00@gmail.com> * test(qa-lab): cover GPT-style broken turns * test: extend macos parallels gateway timeout * build: refresh a2ui bundle hash * fix(hooks): pass workspaceDir in gateway session reset internal hook context (openclaw#64735) * fix(hooks): pass workspaceDir in gateway session reset internal hook context The gateway path (performGatewaySessionReset) omitted workspaceDir when creating the internal hook event, while the plugin hook path (emitGatewayBeforeResetPluginHook) in the same file correctly resolved and passed it. This caused the session-memory handler to fall back to resolveAgentWorkspaceDir from the session key, which for default-agent keys resolves to the shared default workspace instead of the per-agent workspace. Daily notes and memory files were written to the wrong workspace in multi-agent setups. Closes openclaw#64528 * docs(changelog): add session-memory workspace reset note * fix(changelog): remove conflict markers --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * docs(gateway): Document Docker-out-of-Docker Paradox and constraint (openclaw#65473) * docs: Detail Docker-out-of-Docker paradox and host path requirements * docs: fix spelling inside sandboxing.md * fix: grammar typo as suggested by Greptile * Agents: fix Windows drive path join for read/sandbox tools (openclaw#54039) (openclaw#66193) * Agents: fix Windows drive path join for read/sandbox tools (openclaw#54039) * fix(agents): harden Windows file URL path mapping * fix(agents): reject encoded file URL separators * Update CHANGELOG.md --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * test: bound canvas auth helper waits * chore(release): prepare 2026.4.14 beta * build: prune runtime dependency type declarations * fix: include apiKey in codex provider catalog to unblock models.json loading (openclaw#66180) Merged via squash. Prepared head SHA: ce61934 Co-authored-by: hoyyeva <63033505+hoyyeva@users.noreply.github.com> Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com> Reviewed-by: @BruceMacD * fix(slack): align interaction auth with allowlists (openclaw#66028) * fix(slack): align interaction auth with allowlists * fix(slack): address review followups * fix(slack): preserve explicit owners with wildcard * chore: append Claude comments resolution worklog * fix(slack): harden interaction auth with default-deny, mandatory actor binding, and channel type validation - Add interactiveEvent flag to authorizeSlackSystemEventSender for stricter interactive control authorization - Default-deny when no allowFrom or channel users are configured for interactive events (block actions, modals) - Require expectedSenderId for all interactive event types; block actions pass Slack-verified userId, modals pass metadata-embedded userId - Reject ambiguous channel types for interactive events to prevent DM authorization bypass via channel-type fallback - Add comprehensive test coverage for all new behaviors * fix(slack): scope interactive owner/allowFrom enforcement to interactive paths only * fix(slack): preserve no-channel interactive default * Update context-engine-maintenance test * chore: remove USER.md worklog artifact Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * changelog: note Slack interactive auth allowlist alignment (openclaw#66028) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Devin Robison <drobison@nvidia.com> * fix(media): fail closed on attachment canonicalization (openclaw#66022) * fix(media): fail closed on attachment canonicalization * fix(media): clarify attachment skip failures * fix(media): preserve attachment URL fallback * fix(media): preserve getPath URL fallback on blocked local paths * changelog: note media attachment canonicalization fail-closed (openclaw#66022) --------- Co-authored-by: Devin Robison <drobison@nvidia.com> * Guard dangerous gateway config mutations (openclaw#62006) * fix(gateway): guard dangerous config alias * fix(gateway): ignore reordered dangerous flags * fix(gateway): use id-based mapping identity and honor legacy alias baseline * fix(gateway): tighten dangerous config matching * fix(gateway): strip IPv6 brackets in isRemoteGatewayTarget hostname check * fix(gateway): detect tunneled remote targets * fix(gateway): match id-less hook mappings by fingerprint, not index * fix(gateway): detect env-selected remote targets * fix(gateway): resolve remote-target guard from live config, not captured opts * fix(gateway): resolve remote-target guard from live config, not captured opts * fix(gateway): treat loopback OPENCLAW_GATEWAY_URL as local when mode is not remote * fix(gateway): preserve legacy dangerous hook edits * fix(gateway): block dangerous plugin reactivation * fix(gateway): handle dotted plugin IDs in dangerous-flag checks * fix(gateway): honor plugin policy activation * fix(gateway): block remote plugin activation changes via allow/deny/enabled * fix(gateway): broaden loopback url detection * fix(gateway): resolve plugin IDs by longest-prefix match * fix(gateway): block remote slot activation * fix(gateway): preserve legacy mapping identity during id+field transitions * fix(gateway): block remote load-path and channel activation changes * test(gateway): fix remote config mock typing * fix(gateway): guard auto-enabled dangerous plugins * fix(gateway): address P1 review comments on remote gateway mutation guards - Treat all OPENCLAW_GATEWAY_URL targets as remote for mutation guards to prevent SSH tunnel bypasses - Always load config fresh in isRemoteGatewayTargetForAgentTools to detect session changes - Expand remote activation guard to cover auto-enable paths (auth.profiles, models.providers, agents.defaults, agents.list, tools.web.fetch.provider) - Respect plugins.deny in manifest-missing fallback to prevent false negatives - Fix hook mapping identity matching to properly handle id-less mappings by fingerprint - Update tests to reflect new secure behavior for env-sourced gateway URLs * fix(gateway): prevent hook mapping swap attacks via fingerprint-only matching When both current and next tokens have fingerprints, match ONLY by fingerprint. This prevents replacing one dangerous hook mapping with a different one at the same array index from being incorrectly treated as 'already present'. The previous fallback to index-based matching allowed bypasses where an attacker could swap dangerous mappings at the same index without triggering the guard. * fix(gateway): honor allowlist in fallback guard * fix(gateway): treat empty plugin allowlist as unrestricted in manifest-missing fallback * docs: update USER.md worklog for empty-allowlist fix * fix(gateway): resolve review comments — type safety, auto-enable resilience, remote hardening edits * docs: update USER.md worklog for review comment resolution * fix(gateway): block remaining remote setup auto-enable paths * fix(gateway): simplify dangerous config mutation guard to set-diff approach Replace 400+ lines of hook fingerprinting, remote gateway detection, plugin activation tracking, and auto-enable enumeration with a simple set-diff against collectEnabledInsecureOrDangerousFlags — the same enumeration openclaw security audit already uses. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove USER.md audit log from PR Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * changelog: note gateway-tool dangerous config mutation guard (openclaw#62006) --------- Co-authored-by: Devin Robison <drobison@nvidia.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(telegram): persist topic-name cache * test(telegram): cover topic-name cache reload * docs(changelog): note telegram topic-name persistence * fix(telegram): allow topic cache without session runtime * fix(telegram): persist topic cache via default runtime * fix: move telegram topic-cache changelog to unreleased (openclaw#66107) * test: enforce npm pack budget in install smoke * fix: restore pnpm check * test: remove timer dependency from telegram topic cache tests * fix: avoid inline dotenv secrets in systemd unit during service repair (openclaw#66249) (thanks @tmimmanuel) * fix(daemon): avoid inline dotenv secrets in systemd unit during service repair * fix(daemon): sanitize systemd envfile and dedupe state-dir resolution * fix(daemon): fail on multiline dotenv values for systemd envfile * test(daemon): cover systemd envfile staging * fix: keep systemd envfile overrides intact (openclaw#66249) (thanks @tmimmanuel) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * test: cover gateway wake startup gating * test: stabilize gateway wake gating regression * fix: tighten inbound replay typing * test: align feishu replay helper typing * test: update model fallback auth store mock * test: refresh cron and mcp typed fixtures * test: use cron embedded runtime mock * test: mock model fallback source check * fix: align latest main type drift * fix: remove agent config lint suppression * test: align cron runtime seams * test: align agent session resolver mocks * test: align cron model error expectations * test: drop removed agent scope suppression * fix: keep baileys plugin-local * test: align post-rebase full-suite drift * fix: mirror baileys root dependency * test: bound docker fs bridge probes * test: keep telegram cache boundary compatible * fix: cache external plugin catalog lookups in auto-enable (openclaw#66246) (thanks @yfge) * fix: cache external plugin catalog lookups in auto-enable Fixes openclaw#66159 * test: restore readFileSync spy in plugin auto-enable test * refactor: distill plugin auto-enable cache path * fix: cache external plugin catalog lookups in auto-enable (openclaw#66246) (thanks @yfge) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * Agents: clarify local model context preflight (openclaw#66236) Merged via squash. Prepared head SHA: 11bfaf1 Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com> Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com> Reviewed-by: @ImLukeF * fix: harden approvals get timeout handling (openclaw#66239) (thanks @neeravmakwana) * fix(cli): harden approvals get timeout handling * fix(cli): sanitize approvals timeout notes * fix(cli): distill approvals timeout note --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * fix: honor configured store limits (openclaw#66240) (thanks @neeravmakwana) * fix(media): honor configured store limits * fix(media): report effective source limits * refactor(media): distill configured limit wiring --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * fix(browser): relax default hostname SSRF guard * fix(browser): use loopback policy for json-new fallback * fix(browser): preserve explicit strict SSRF config * fix: add browser SSRF follow-up changelog entry (openclaw#66386) * fix(browser): preserve legacy strict SSRF alias * feat(active-memory): instrument embedded runs --------- Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: Frank Yang <frank.ekn@gmail.com> Co-authored-by: Bob <dutifulbob@gmail.com> Co-authored-by: dutifulbob <261991368+dutifulbob@users.noreply.github.com> Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com> Co-authored-by: mazhe-nerd <106217973+mazhe-nerd@users.noreply.github.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org> Co-authored-by: Minijus-Sa <minijus.savickas@hostinger.com> Co-authored-by: EVA <admin@100yen.org> Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Co-authored-by: Brian <95547369+zhuisDEV@users.noreply.github.com> Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net> Co-authored-by: Mariano <132747814+mbelinky@users.noreply.github.com> Co-authored-by: Mariano Belinky <mariano@mb-server-643.local> Co-authored-by: Omar Shahine <omarshahine@users.noreply.github.com> Co-authored-by: Lobster <lobster@shahine.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Ptah.ai <11701+ptahdunbar@users.noreply.github.com> Co-authored-by: Ayaan Zaidi <hi@obviy.us> Co-authored-by: Pavan Kumar Gondhi <pgondhi@nvidia.com> Co-authored-by: pashpashpash <nik@vault77.ai> Co-authored-by: 屈定 <niudear@foxmail.com> Co-authored-by: 屈定 <mrdear@users.noreply.github.com> Co-authored-by: Altay <altay@uinaf.dev> Co-authored-by: Agustin Rivera <31522568+eleqtrizit@users.noreply.github.com> Co-authored-by: Devin Robison <drobison@nvidia.com> Co-authored-by: zsx <git@zsxsoft.com> Co-authored-by: rafaelreis-r <57492577+rafaelreis-r@users.noreply.github.com> Co-authored-by: Byron <loong0306@163.com> Co-authored-by: loong0306 <loong0306@gmail.com> Co-authored-by: Nova <nova@openknot.ai> Co-authored-by: Val Alexander <bunsthedev@gmail.com> Co-authored-by: zhangfan49 <zhangfan49@baidu.com> Co-authored-by: mbelinky <mbelinky@users.noreply.github.com> Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com> Co-authored-by: Xiaoshuai Zhang <i@jetd.one> Co-authored-by: jetd1 <15795935+jetd1@users.noreply.github.com> Co-authored-by: grp06 <1573959+grp06@users.noreply.github.com> Co-authored-by: Josh Lehman <josh@martian.engineering> Co-authored-by: ShihChi Huang <shh@theonlyperson.com> Co-authored-by: @zimeg <zim@o526.net> Co-authored-by: George Pickett <gpickett00@gmail.com> Co-authored-by: Subash Natarajan <suboss87@gmail.com> Co-authored-by: Joe LaPenna <jlapenna@gmail.com> Co-authored-by: ly85206559 <ly85206559@163.com> Co-authored-by: Eva H <63033505+hoyyeva@users.noreply.github.com> Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com> Co-authored-by: tmimmanuel <14046872+tmimmanuel@users.noreply.github.com> Co-authored-by: 拐爷&&老拐瘦 <geyunfei@gmail.com> Co-authored-by: Luke <92253590+ImLukeF@users.noreply.github.com> Co-authored-by: Neerav Makwana <neeravmakwana@gmail.com> Co-authored-by: Bastion <bastion@agents.angventures.io>
Summary
redactConfigSnapshot()spread...snapshotthen only overwroteconfigandresolvedwith redacted copies, leavingsourceConfigandruntimeConfig(the canonical alias fields) pointing to the original unredacted objects. Any caller reading those fields received plaintext secrets.config.getgateway RPC serializes the full snapshot output to authenticated clients. A session withoperator.readscope could extract all stored secrets (API keys, auth tokens, channel credentials) via the unredacted alias fields.redactConfigSnapshotnow explicitly overwritessourceConfig(set toredactedResolved) andruntimeConfig(set toredactedConfig) in both the valid-snapshot and invalid-snapshot return paths. Test coverage added for both new fields.config,resolved,raw, andparsedis unchanged. No gateway RPC surface, scope model, or schema changed.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
redactObject()returns new objects rather than mutating in place. The object spread copies the originalsourceConfigandruntimeConfigreferences, and the subsequent explicit overrides only covered the deprecated aliases (config,resolved), not the canonical fields.result.sourceConfigorresult.runtimeConfigwere redacted — only the deprecated alias fields were checked.sourceConfig/runtimeConfigwere introduced as canonical replacements forresolved/configbut the redaction function was not updated in lockstep.Regression Test Plan (if applicable)
src/config/redact-snapshot.test.tsresult.sourceConfigandresult.runtimeConfigcontainREDACTED_SENTINELfor known-sensitive values; both alias pairs are referentially equal (sourceConfig === resolved,runtimeConfig === config).redactConfigSnapshotwithout any gateway layer.result.configandresult.resolvedwere previously asserted.User-visible / Behavior Changes
None.
sourceConfigandruntimeConfigwere already supposed to be redacted; this makes the behavior match the documented contract.Diagram (if applicable)
Security Impact (required)
sourceConfigandruntimeConfigfields are now properly redacted before being returned byredactConfigSnapshot.Repro + Verification
Environment
gateway.auth.tokenorchannels.discord.tokensetSteps
pnpm test src/config/redact-snapshot.test.tsresult.sourceConfigandresult.runtimeConfigboth containREDACTED_SENTINELresult.sourceConfig === result.resolved,result.runtimeConfig === result.configExpected
Actual
Evidence
New test cases added to
redact-snapshot.test.tsdirectly assert the previously-unredacted fields now containREDACTED_SENTINEL.Human Verification (required)
{}); referential equality maintained between alias pairs.sourceConfig === resolvedandruntimeConfig === configidentity preserved so downstream code relying on reference equality is unaffected.Review Conversations
Compatibility / Migration
Risks and Mitigations
sourceConfig/runtimeConfigto be unredacted (incorrect usage) would now receive redacted values.redactConfigSnapshotand no code path depends on receiving unredacted aliases from this function.