* fix(whatsapp): wrap JSON.parse with try-catch in auth store and test helpers
Add defensive try-catch around JSON.parse calls in WhatsApp extension
to prevent crashes from corrupted state files.
- restoreCredsFromBackupIfNeeded: wrap creds.json/backup validation
JSON.parse with try-catch; corrupted creds.json now properly falls
through to backup restoration instead of skipping it entirely
- updateLastRouteMock: wrap JSON.parse with try-catch, initialize
empty store on corrupted file
* test(whatsapp): add regression test for malformed creds.json longer than one byte
- Add a focused regression test for the exact case ClawSweeper
flagged: readWebCredsJsonRawSync returns non-null content for
files with stat.size > 1, so malformed JSON like "{x" (2 bytes)
reaches JSON.parse — the inner try-catch now catches the parse
failure and falls through to backup restoration
- Without this patch, JSON.parse("{x") throws to the outer catch
and restoreCredsFromBackupIfNeeded returns false, skipping backup
🦞 diamond lobster: L2 evidence (real function call + real filesystem objects)
Ref. https://github.com/openclaw/openclaw/pull/99070
* fix(whatsapp): restore malformed creds from backup
Co-authored-by: LeonidasLux <LeonidasLux@users.noreply.github.com>
* docs(changelog): defer credential recovery entry to aggregate
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: LeonidasLux <LeonidasLux@users.noreply.github.com>
(cherry picked from commit 42464de58d)
* fix(whatsapp): thread authDir through command authorization and owner bypass for LID JID resolution
WhatsApp group commands (/new, /stop) can be ignored when Baileys reports the sender as a LID JID (@lid) instead of a phone JID (@s.whatsapp.net). The resolveWhatsAppCommandAuthorized() and isOwnerSender() functions called getSelfIdentity/getSenderIdentity without passing authDir, so the LID-to-phone reverse mapping could not happen.
Fix: thread account.authDir through both command authorization and group owner-bypass identity resolution paths so that LID JIDs are properly resolved to phone E.164 identities before owner/allowlist checks.
* fix(whatsapp): replace deprecated top-level fields with admission overrides in LID JID test
(cherry picked from commit 85f7834852)
The Google Meet OAuth login binds a fixed localhost:8085 callback listener
and let listener failures propagate, so meet auth login aborted entirely when
port 8085 was already in use. The sibling Gemini CLI OAuth path already
recovers by switching to the manual copy/paste flow on EADDRINUSE/listen
errors; bring Google Meet to parity by catching listener errors and reusing
the existing manual-paste handler instead of failing the login.
(cherry picked from commit 38ab207591)
When a Feishu channel has top-level appId/appSecret using SecretRef
format and sub-accounts with their own inline appSecret, the secrets
resolver marks the top-level SecretRef as inactive because
isBaseFieldActiveForChannelSurface only checks whether any explicit
account inherits the field.
Feishu account listing always creates an implicit default account from
top-level credentials. The fix detects this implicit default account
and keeps the top-level appSecret active accordingly, without changing
the shared channel secret helper semantics for other channels.
Fixes#96929
Signed-off-by: 赵旺0668001248 <0668001248@duomai.com>
(cherry picked from commit 4e7992cc9b)
Wrap the slack outbound sanitizeText hook with sanitizeAssistantVisibleText so assistant internal tool-trace scaffolding is stripped before delivery, matching the sibling channel fixes under #90684 (Telegram #95774, Google Chat #95084, IRC #97214).
(cherry picked from commit cd6d0f9b00)
Wrap the matrix outbound sanitizeText hook with sanitizeAssistantVisibleText so assistant internal tool-trace scaffolding is stripped before delivery, matching the sibling channel fixes under #90684 (Telegram #95774, Google Chat #95084, IRC #97214).
(cherry picked from commit 25490d4c42)
* fix(irc): sanitize internal tool-trace lines from outbound text
* fix(irc): sanitize internal tool-trace lines from outbound text
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit ddedf13190)
* fix(tlon): bound error response body reads to prevent OOM
Replace bare response.text() on non-ok paths with readResponseTextLimited
capped at 16 KiB so a hostile or misconfigured Urbit ship cannot force the
gateway to buffer an arbitrary-size error body into process memory.
Affected paths:
- pokeUrbitChannel (channel-ops.ts)
- channel.runtime.ts poke path
- sendSubscription (sse-client.ts)
* fix(tlon): fix lint issues in error-body-boundary test
- Remove unused beforeEach import
- Wrap if/else bodies in braces (curly)
- Use block body for Promise executors (no-promise-executor-return)
* fix(types): resolve pre-existing TS test type errors
- Fix TS2493 tuple type errors in server-cron-notifications and
server-cron tests by adding explicit type annotations on mock.calls
- Fix TS2322 in anthropic.test.ts by adding as const to resource
content block type
* chore: trigger CI
(cherry picked from commit 8abd5d4071)
* fix(discord): bound happy-path API response reads to prevent OOM
Replace the unbounded res.text() call in requestDiscord's success path with
readResponseTextLimited capped at 4 MiB. Discord channel message lists and
attachment payloads can accumulate to large sizes; without a cap the process
can exhaust available memory. The error path already used readResponseTextLimited
with DISCORD_API_ERROR_BODY_LIMIT_BYTES — this applies the same guard to the
happy path using a separate DISCORD_API_RESPONSE_BODY_LIMIT_BYTES constant
sized appropriately for valid API payloads.
* test(discord): upgrade to real HTTP server proof for bound requestDiscord
* fix(discord): remove unnecessary type assertion in bound test
(cherry picked from commit fca15641db)
* fix(nextcloud-talk): bound external send/reaction response reads to prevent OOM
Nextcloud Talk talks to self-hosted servers whose HTTP responses are not
trusted to be small. The send and reaction paths buffered three external
bodies without any byte cap:
- success JSON via await response.json()
- send error text via await response.text()
- reaction error text via await response.text()
A hostile or misbehaving Nextcloud endpoint could stream an unbounded body
(no content-length) into memory, pressuring or hanging the plugin/provider
path. Cap success JSON at 16 MiB via readResponseWithLimit and collapse error
bodies to an 8 KiB readResponseTextSnippet, cancelling the stream on overflow.
The 'message sent but receipt JSON unreadable -> unknown' fallback is
preserved (an over-limit body now also routes through the existing catch).
This is the symmetric counterpart to the #95103/#95108 response-limit
campaign, reusing the shared @openclaw/media-core helpers (newly re-exported
from plugin-sdk/response-limit-runtime for plugin consumers).
* fix(nextcloud-talk): bound error bodies via public readResponseTextLimited (no new plugin-SDK surface)
Re-exporting readResponseTextSnippet from plugin-sdk/response-limit-runtime
pushed the public plugin-SDK export count past its surface budget, failing
plugin-sdk-surface-report.test.ts. Drop that re-export and instead bound the
Nextcloud Talk send/reaction error bodies through the already-public
readResponseTextLimited (openclaw/plugin-sdk/provider-http), collapsing the
bounded 8 KiB prefix to a short, log-safe snippet locally. Behavior is
unchanged for callers; no new plugin-SDK surface is introduced.
Success JSON still reads through readResponseWithLimit (16 MiB cap). The
committed bounded-response-reads Vitest suite continues to prove the caps
hold against 17 MiB streamed bodies with no content-length.
* fix(nextcloud-talk): reuse shared readProviderJsonResponse for send success JSON
The send success receipt parsed JSON by hand via readResponseWithLimit + a
local NEXTCLOUD_TALK_JSON_MAX_BYTES cap + JSON.parse(TextDecoder.decode(...)),
duplicating the shared provider-http helper that the sibling room-info.ts and
bot-preflight.ts already use. extensions/AGENTS.md forbids re-implementing
shared helpers locally.
Swap the hand-rolled block for the one-stop
readProviderJsonResponse<{ ocs?: ... }>(response, "Nextcloud Talk send"), which
reads through the same bounded reader and throws on overflow/malformed JSON, so
the outer try/catch still keeps the "unknown" receipt and behavior is
equivalent. The error path keeps readResponseTextLimited (text, not JSON).
(cherry picked from commit d577cb2fe9)
* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse
Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.
What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
delegates to readProviderJsonResponse. Removed the local try/catch
wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
delegates to readProviderJsonResponse. Error message preserved.
Removed the local try/catch wrapper.
This PR applies the same pattern as Alix-007's #96042, #96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.
* fix(googlechat): add inline bounded-read regression tests
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(googlechat): remove unused variable flagged by oxlint
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(googlechat): bound api error body reads
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
(cherry picked from commit 4f3d81b918)
* fix(openai): bound Codex OAuth token response body reads with readResponseWithLimit
Replace unbounded response.arrayBuffer() in postTokenForm with
readResponseWithLimit using a 1 MiB cap to prevent OOM from oversized
token endpoint responses. Add real node:http loopback server tests.
* fix(openai): wrap readResponseWithLimit result in Uint8Array for TS BodyInit compat
- Fixes TS2345: Buffer<ArrayBufferLike> not assignable to BodyInit
- Resolves check-prod-types, check-test-types, and
check-additional-extension-package-boundary CI failures
Ref. https://github.com/openclaw/openclaw/pull/99479
* test(openai): verify OAuth response release
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit a89fe705b8)
* fix(discord): bound gateway metadata response body reads to prevent OOM
The materializeGuardedResponse helper in the Discord gateway metadata path
buffered the full upstream Response body via response.arrayBuffer() without
any size cap. A malicious or malfunctioning /gateway/bot endpoint that returns
an oversized payload could exhaust gateway memory.
Replace arrayBuffer() with readResponseWithLimit(4 MiB), consistent with
DISCORD_API_RESPONSE_BODY_LIMIT_BYTES in api.ts. Overflow throws an Error
with the byte counts.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(discord): wrap readResponseWithLimit result in Uint8Array for type compat
readResponseWithLimit returns Buffer which is not assignable to BodyInit in
the undici Response constructor type. Wrap in new Uint8Array() to satisfy the
boundary dts check. Also remove testExports export and mock fetchWithSsrFGuard
in tests via vi.hoisted + vi.mock to avoid leaking internal test-only exports.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(discord): tighten gateway metadata proof
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit fc77c2b04b)
The Discord REST main response path read the body with an unbounded
await response.text() before JSON-parsing it. A controlled or hijacked
endpoint could stream an arbitrarily large body and exhaust memory (OOM).
Wrap the read in the canonical readResponseWithLimit helper with an 8 MiB
cap (well above any legitimate Discord JSON payload) plus an idle timeout
tied to the request timeout, so the stream is cancelled at the cap or on
stall instead of buffering unbounded. Normal payloads still parse fully.
This mirrors PR #95108 which bounded the analogous Anthropic Messages
error-response read with the same helper.
(cherry picked from commit 2d2a50c00d)
* chore(release): close out 2026.6.10 on main
* chore(release): align native app metadata for 2026.6.10
* chore(release): sync Android 2026.6.10 notes
* docs(changelog): preserve 2026.6.9 history
* docs(changelog): preserve 2026.6.9 history
* fix(workboard): hide archived cards in CLI list by default
The `openclaw workboard list` CLI printed soft-archived cards, while the
`workboard_list` agent tool and the `/workboard list` command both hide
cards with `metadata.archivedAt` set unless archives are requested. Users
who archived cards still saw them in CLI output and assumed archive failed.
Filter archived cards by default in the CLI list handler and add an
`--include-archived` flag mirroring the tool's `includeArchived` option, so
all three list surfaces share one default. Docs updated to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(workboard): preserve json list archive visibility
* fix(workboard): preserve json list archive visibility
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>