Skip to content

fix(signal): guard containerRestRequest JSON.parse against malformed responses#98073

Merged
vincentkoc merged 3 commits into
openclaw:mainfrom
lsr911:fix/signal-json-parse-guard
Jun 30, 2026
Merged

fix(signal): guard containerRestRequest JSON.parse against malformed responses#98073
vincentkoc merged 3 commits into
openclaw:mainfrom
lsr911:fix/signal-json-parse-guard

Conversation

@lsr911

@lsr911 lsr911 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

extensions/signal/src/client-container.ts:262 calls JSON.parse(text) on the Signal REST container response body without try/catch. The body is already bounded by readProviderTextResponse (16 MiB shared provider cap), but a malformed JSON body within that cap throws unhandled SyntaxError.

This is error normalization: wrapping the parse in try/catch produces a stable Error("Signal REST returned malformed JSON") instead of a raw SyntaxError, giving callers consistent error handling.

Changes

  • extensions/signal/src/client-container.ts: wrap JSON.parse(text) in try/catch → Error("Signal REST returned malformed JSON")
  • extensions/signal/src/client-container.test.ts: tighten existing assertion to the specific error message
  • test/_proof_signal_json_guard.mts: real HTTP server proof (L2)

Label: bugfix | merge-risk: 🟢 minimal | AI-assisted

Evidence

Real HTTP server proof — local node:http server returns malformed JSON (L2)

Starts a local node:http server on 127.0.0.1:0, has it return NOT JSON {{{ with content-type: application/json, then calls containerRestRequest against it through the real fetch stack. No mock, no global override.

$ node --import tsx test/_proof_signal_json_guard.mts

PASS  malformed JSON: throws Error :: type=Error
PASS  malformed JSON: message describes malformed JSON :: msg="Signal REST returned malformed JSON"
PASS  malformed JSON: NOT raw SyntaxError :: type=Error

[proof] 3 PASS, 0 FAIL

Unit test

$ pnpm exec vitest run extensions/signal/src/client-container.test.ts

 Test Files  1 passed (1)
      Tests  53 passed (53)
   Duration  18.28s

@openclaw-barnacle openclaw-barnacle Bot added channel: signal Channel integration: signal size: XS labels Jun 30, 2026
@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 1:41 PM ET / 17:41 UTC.

Summary
The PR wraps Signal container REST success-body JSON parsing in a stable malformed-JSON error and tightens the colocated malformed-response test assertion.

PR surface: Source +4, Tests 0. Total +4 across 2 files.

Reproducibility: yes. Source inspection shows current main and v2026.6.11 pass non-empty Signal REST success text to bare JSON.parse, and the PR body provides terminal proof through a real local HTTP server returning malformed JSON.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/signal/src/client-container.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: canonical
Canonical: #98073
Summary: This PR is the focused canonical candidate for Signal container malformed-JSON normalization; related merged PRs are provenance or adjacent hardening, not replacements.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • [P2] No repair lane is needed; the PR has no actionable findings and should proceed through ordinary maintainer review and exact-head checks.

Security
Cleared: The diff only normalizes Signal REST JSON parsing and updates a colocated assertion; it adds no dependency, workflow, permission, credential, package-resolution, download, or secret-handling surface.

Review details

Best possible solution:

Land the narrow Signal container REST parse normalization after ordinary maintainer review, keeping the fix local to containerRestRequest and preserving empty-body behavior.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main and v2026.6.11 pass non-empty Signal REST success text to bare JSON.parse, and the PR body provides terminal proof through a real local HTTP server returning malformed JSON.

Is this the best way to solve the issue?

Yes. containerRestRequest is the central owner boundary for Signal container REST success bodies; using the shared JSON reader directly would need extra handling to preserve the existing empty-body-to-undefined contract.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 5c4e478df4ef.

Label changes

Label justifications:

  • P2: This is a normal-priority Signal container runtime bugfix with limited channel-specific blast radius.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal output from a local real HTTP server returning malformed JSON through the real fetch path, which is sufficient for this non-visual runtime error-normalization change.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output from a local real HTTP server returning malformed JSON through the real fetch path, which is sufficient for this non-visual runtime error-normalization change.
Evidence reviewed

PR surface:

Source +4, Tests 0. Total +4 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 5 1 +4
Tests 1 1 1 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 6 2 +4

What I checked:

Likely related people:

  • Hua688: Authored the merged Signal container REST/WebSocket support PR that added the container helper and colocated tests under review. (role: feature introducer; confidence: high; commits: dff4a04c1f5f, b49910663044; files: extensions/signal/src/client-container.ts, extensions/signal/src/client-container.test.ts, extensions/signal/src/client-adapter.ts)
  • steipete: Merged the original Signal container support PR and authored several follow-up hardening commits in the same transport area. (role: feature reviewer and merger; confidence: high; commits: dff4a04c1f5f, 55db92d5b2b3, dcee8aaa480f; files: extensions/signal/src/client-container.ts, extensions/signal/src/client-container.test.ts, docs/channels/signal.md)
  • Alix-007: Authored the merged bounded-read hardening for the same Signal container REST helper shortly before this PR. (role: recent adjacent contributor; confidence: high; commits: d75b9ea642bc, dd6143f60c24; files: extensions/signal/src/client-container.ts, extensions/signal/src/client-container.test.ts)
  • vincentkoc: Merged the bounded-read hardening PR for this helper and authored the current branch cleanup that removed the temporary proof script from the final diff. (role: recent adjacent merger and cleanup contributor; confidence: medium; commits: dd6143f60c24, fbfd2aac00fb; files: extensions/signal/src/client-container.ts, extensions/signal/src/client-container.test.ts, test/_proof_signal_json_guard.mts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jun 30, 2026
@lsr911
lsr911 force-pushed the fix/signal-json-parse-guard branch from 1631545 to bc3f4a2 Compare June 30, 2026 07:54
@lsr911

lsr911 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 30, 2026
@lsr911
lsr911 force-pushed the fix/signal-json-parse-guard branch from bc3f4a2 to 066c2dd Compare June 30, 2026 08:24
@lsr911

lsr911 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 30, 2026
@lsr911

lsr911 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@openclaw-barnacle openclaw-barnacle Bot added triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. size: S and removed size: XS triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jun 30, 2026
@lsr911
lsr911 force-pushed the fix/signal-json-parse-guard branch from 50ed313 to 066c2dd Compare June 30, 2026 11:13
@lsr911

lsr911 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

1 similar comment
@lsr911

lsr911 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@vincentkoc
vincentkoc force-pushed the fix/signal-json-parse-guard branch from b8cfbf8 to fbfd2aa Compare June 30, 2026 17:30
@vincentkoc
vincentkoc merged commit 7d98ad2 into openclaw:main Jun 30, 2026
90 checks passed
@vincentkoc

Copy link
Copy Markdown
Member

Merged via squash.

giodl73-repo added a commit to giodl73-repo/openclaw that referenced this pull request Jun 30, 2026
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 1, 2026
runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 /
telegram-ingress openclaw#98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 1, 2026
…responses (openclaw#98073)

* fix(signal): guard containerRestRequest JSON.parse against malformed responses

Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.

On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).

Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* fix(signal): add real HTTP server proof for malformed JSON guard

Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it.  This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).

Proof output:
  PASS  malformed JSON: throws Error :: type=Error
  PASS  malformed JSON: message describes malformed JSON
  PASS  malformed JSON: NOT raw SyntaxError

Signed-off-by: lsr911 <[email protected]>
Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* test(signal): remove committed proof script

---------

Signed-off-by: lsr911 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 1, 2026
runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 /
telegram-ingress openclaw#98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
…responses (openclaw#98073)

* fix(signal): guard containerRestRequest JSON.parse against malformed responses

Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.

On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).

Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* fix(signal): add real HTTP server proof for malformed JSON guard

Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it.  This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).

Proof output:
  PASS  malformed JSON: throws Error :: type=Error
  PASS  malformed JSON: message describes malformed JSON
  PASS  malformed JSON: NOT raw SyntaxError

Signed-off-by: lsr911 <[email protected]>
Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* test(signal): remove committed proof script

---------

Signed-off-by: lsr911 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
…responses (openclaw#98073)

* fix(signal): guard containerRestRequest JSON.parse against malformed responses

Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.

On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).

Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* fix(signal): add real HTTP server proof for malformed JSON guard

Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it.  This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).

Proof output:
  PASS  malformed JSON: throws Error :: type=Error
  PASS  malformed JSON: message describes malformed JSON
  PASS  malformed JSON: NOT raw SyntaxError

Signed-off-by: lsr911 <[email protected]>
Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* test(signal): remove committed proof script

---------

Signed-off-by: lsr911 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 2, 2026
…API bodies

fetchJson in telegram-ingress-worker.runtime.ts parsed the Bot API response
body with JSON.parse but did not catch SyntaxError. A non-JSON body (HTML
error page, empty, or truncated from a CDN, reverse proxy, or TLS MITM) made
the SyntaxError bubble to the long-poll loop, where
isRecoverableTelegramNetworkError judged it non-recoverable (SyntaxError is
not in the recoverable code/name/message sets), so the loop re-threw and the
isolated ingress worker exited — silently dropping the Telegram channel until
manual restart.

Wrap JSON.parse in try/catch and throw a descriptive Error carrying statusCode
(matching the matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 pattern). Add
"malformed json" to RECOVERABLE_MESSAGE_SNIPPETS so the polling/webhook
contexts back off and retry instead of exiting; send context stays
conservative (allowMessageMatch defaults false) to avoid duplicate-message
retries.

Co-Authored-By: Claude <[email protected]>
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 2, 2026
runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 /
telegram-ingress openclaw#98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 3, 2026
…API bodies

fetchJson in telegram-ingress-worker.runtime.ts parsed the Bot API response
body with JSON.parse but did not catch SyntaxError. A non-JSON body (HTML
error page, empty, or truncated from a CDN, reverse proxy, or TLS MITM) made
the SyntaxError bubble to the long-poll loop, where
isRecoverableTelegramNetworkError judged it non-recoverable (SyntaxError is
not in the recoverable code/name/message sets), so the loop re-threw and the
isolated ingress worker exited — silently dropping the Telegram channel until
manual restart.

Wrap JSON.parse in try/catch and throw a descriptive Error carrying statusCode
(matching the matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 pattern). Add
"malformed json" to RECOVERABLE_MESSAGE_SNIPPETS so the polling/webhook
contexts back off and retry instead of exiting; send context stays
conservative (allowMessageMatch defaults false) to avoid duplicate-message
retries.

Co-Authored-By: Claude <[email protected]>
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 3, 2026
runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 /
telegram-ingress openclaw#98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
…responses (openclaw#98073)

* fix(signal): guard containerRestRequest JSON.parse against malformed responses

Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.

On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).

Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* fix(signal): add real HTTP server proof for malformed JSON guard

Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it.  This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).

Proof output:
  PASS  malformed JSON: throws Error :: type=Error
  PASS  malformed JSON: message describes malformed JSON
  PASS  malformed JSON: NOT raw SyntaxError

Signed-off-by: lsr911 <[email protected]>
Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* test(signal): remove committed proof script

---------

Signed-off-by: lsr911 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
openclaw-clownfish Bot pushed a commit that referenced this pull request Jul 6, 2026
…ut (#98381)

* fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout

runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix #97973 / sms #97999 / signal #98073 /
telegram-ingress #98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): preserve cause in qmd mcporter JSON.parse guard

Add { cause: err } to the re-thrown Error to satisfy the preserve-caught-error
lint rule; the original SyntaxError is now chained, improving diagnosability.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): redact raw stdout from qmd mcporter error (security-boundary)

ClawSweeper flagged that the previous error message exposed raw mcporter
stdout (first 200 chars) before session visibility filtering, which could
leak sensitive content. Drop the stdout preview from the thrown message;
keep the original SyntaxError as `cause` for diagnostics so the parse-failure
reason is still reachable without surfacing unfiltered subprocess output.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): keep qmd mcporter error message generic (no raw stdout leak)

The SyntaxError thrown by JSON.parse embeds a snippet of the raw input in its
message (e.g. Unexpected token '<', then the raw bytes). Including that
SyntaxError message in the thrown Error would surface unfiltered mcporter
stdout before session visibility filtering. Drop the parse-error message from
the thrown Error; keep the original SyntaxError as cause for developer
diagnostics only.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): keep qmd mcporter cause generic (no raw stdout leak via formatErrorMessage)

formatErrorMessage walks the .cause chain into the user-visible path.
Keeping the JSON.parse SyntaxError on .cause leaked its embedded raw
stdout snippet through formatErrorMessage even with a generic message.
Give the cause a generic message too; the raw snippet no longer reaches
the user.

Co-Authored-By: Claude <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
…ut (openclaw#98381)

* fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout

runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 /
telegram-ingress openclaw#98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): preserve cause in qmd mcporter JSON.parse guard

Add { cause: err } to the re-thrown Error to satisfy the preserve-caught-error
lint rule; the original SyntaxError is now chained, improving diagnosability.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): redact raw stdout from qmd mcporter error (security-boundary)

ClawSweeper flagged that the previous error message exposed raw mcporter
stdout (first 200 chars) before session visibility filtering, which could
leak sensitive content. Drop the stdout preview from the thrown message;
keep the original SyntaxError as `cause` for diagnostics so the parse-failure
reason is still reachable without surfacing unfiltered subprocess output.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): keep qmd mcporter error message generic (no raw stdout leak)

The SyntaxError thrown by JSON.parse embeds a snippet of the raw input in its
message (e.g. Unexpected token '<', then the raw bytes). Including that
SyntaxError message in the thrown Error would surface unfiltered mcporter
stdout before session visibility filtering. Drop the parse-error message from
the thrown Error; keep the original SyntaxError as cause for developer
diagnostics only.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): keep qmd mcporter cause generic (no raw stdout leak via formatErrorMessage)

formatErrorMessage walks the .cause chain into the user-visible path.
Keeping the JSON.parse SyntaxError on .cause leaked its embedded raw
stdout snippet through formatErrorMessage even with a generic message.
Give the cause a generic message too; the raw snippet no longer reaches
the user.

Co-Authored-By: Claude <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Rorqualx pushed a commit to Rorqualx/cortex that referenced this pull request Jul 6, 2026
…responses (openclaw#98073)

* fix(signal): guard containerRestRequest JSON.parse against malformed responses

Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.

On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).

Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* fix(signal): add real HTTP server proof for malformed JSON guard

Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it.  This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).

Proof output:
  PASS  malformed JSON: throws Error :: type=Error
  PASS  malformed JSON: message describes malformed JSON
  PASS  malformed JSON: NOT raw SyntaxError

Signed-off-by: lsr911 <[email protected]>
Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* test(signal): remove committed proof script

---------

Signed-off-by: lsr911 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
(cherry picked from commit 7d98ad2)
miorbnli added a commit to miorbnli/openclaw that referenced this pull request Jul 8, 2026
…API bodies

fetchJson in telegram-ingress-worker.runtime.ts parsed the Bot API response
body with JSON.parse but did not catch SyntaxError. A non-JSON body (HTML
error page, empty, or truncated from a CDN, reverse proxy, or TLS MITM) made
the SyntaxError bubble to the long-poll loop, where
isRecoverableTelegramNetworkError judged it non-recoverable (SyntaxError is
not in the recoverable code/name/message sets), so the loop re-threw and the
isolated ingress worker exited — silently dropping the Telegram channel until
manual restart.

Wrap JSON.parse in try/catch and throw a descriptive Error carrying statusCode
(matching the matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 pattern). Add
"malformed json" to RECOVERABLE_MESSAGE_SNIPPETS so the polling/webhook
contexts back off and retry instead of exiting; send context stays
conservative (allowMessageMatch defaults false) to avoid duplicate-message
retries.

Co-Authored-By: Claude <[email protected]>
Rorqualx pushed a commit to Rorqualx/cortex that referenced this pull request Jul 8, 2026
…responses (openclaw#98073)

* fix(signal): guard containerRestRequest JSON.parse against malformed responses

Wrap JSON.parse(text) in containerRestRequest with try/catch to prevent a malformed Signal REST container response from throwing an unhandled SyntaxError.

On parse failure, throw a descriptive Error. The success body is already bounded by readProviderTextResponse (16 MiB cap, D1 protection).

Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* fix(signal): add real HTTP server proof for malformed JSON guard

Starts a local node:http server returning malformed JSON, then calls
containerRestRequest against it.  This exercises the actual changed
try/catch code path through the real fetch stack (no mock override).

Proof output:
  PASS  malformed JSON: throws Error :: type=Error
  PASS  malformed JSON: message describes malformed JSON
  PASS  malformed JSON: NOT raw SyntaxError

Signed-off-by: lsr911 <[email protected]>
Co-Authored-By: Claude <[email protected]>
Signed-off-by: lsr911 <[email protected]>

* test(signal): remove committed proof script

---------

Signed-off-by: lsr911 <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
(cherry picked from commit 7d98ad2)
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…ut (openclaw#98381)

* fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout

runQmdSearchViaMcporter parsed mcporter subprocess stdout with JSON.parse
outside the runMcporter try/catch (qmd-manager.ts:2722). A non-JSON stdout
(daemon warning bleeding onto stdout, output truncated by maxOutputChars, CLI
killed early, or flag mismatch) threw a raw SyntaxError that propagated
uncaught out of runQmdSearchViaMcporter, surfacing in agent logs as a
context-free SyntaxError with no hint of the actual mcporter failure.

Wrap JSON.parse in try/catch and throw a typed Error carrying a stdout snippet
(matching the guard pattern already used in parseListedCollections in this
file, and the recent matrix openclaw#97973 / sms openclaw#97999 / signal openclaw#98073 /
telegram-ingress openclaw#98372 JSON.parse guard series).

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): preserve cause in qmd mcporter JSON.parse guard

Add { cause: err } to the re-thrown Error to satisfy the preserve-caught-error
lint rule; the original SyntaxError is now chained, improving diagnosability.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): redact raw stdout from qmd mcporter error (security-boundary)

ClawSweeper flagged that the previous error message exposed raw mcporter
stdout (first 200 chars) before session visibility filtering, which could
leak sensitive content. Drop the stdout preview from the thrown message;
keep the original SyntaxError as `cause` for diagnostics so the parse-failure
reason is still reachable without surfacing unfiltered subprocess output.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): keep qmd mcporter error message generic (no raw stdout leak)

The SyntaxError thrown by JSON.parse embeds a snippet of the raw input in its
message (e.g. Unexpected token '<', then the raw bytes). Including that
SyntaxError message in the thrown Error would surface unfiltered mcporter
stdout before session visibility filtering. Drop the parse-error message from
the thrown Error; keep the original SyntaxError as cause for developer
diagnostics only.

Co-Authored-By: Claude <[email protected]>

* fix(memory-core): keep qmd mcporter cause generic (no raw stdout leak via formatErrorMessage)

formatErrorMessage walks the .cause chain into the user-visible path.
Keeping the JSON.parse SyntaxError on .cause leaked its embedded raw
stdout snippet through formatErrorMessage even with a generic message.
Give the cause a generic message too; the raw snippet no longer reaches
the user.

Co-Authored-By: Claude <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: signal Channel integration: signal P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants