Skip to content

fix(whatsapp): strip control characters from outbound document fileName#77114

Merged
mcaxtr merged 4 commits into
openclaw:mainfrom
masatohoshino:feature/openclaw-whatsapp-document-filename-sanitize
May 28, 2026
Merged

fix(whatsapp): strip control characters from outbound document fileName#77114
mcaxtr merged 4 commits into
openclaw:mainfrom
masatohoshino:feature/openclaw-whatsapp-document-filename-sanitize

Conversation

@masatohoshino

@masatohoshino masatohoshino commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: createWebSendApi document branch applied only .trim() to sendOptions?.fileName before passing it to Baileys; a caller supplying a fileName containing CR, LF, or other C0/DEL control characters could embed those bytes in the outbound document message metadata, enabling CWE-93-style header injection via Baileys' HTTP-like send path.
  • Why it matters: The fileName value originates from documentMessage.fileName on the inbound WhatsApp wire (forwarded through monitor.ts), so a message sender can supply arbitrary bytes. The old code did not sanitize this surface.
  • What changed: resolveWhatsAppDocumentFileName() in extensions/whatsapp/src/document-filename.ts now strips \x00-\x1f and \x7f (all C0 control characters + DEL) from fileName before .trim(), and falls back to a MIME-derived filename (e.g., "file.pdf" for application/pdf) when the stripped result is empty. Three tests in extensions/whatsapp/src/document-filename.test.ts cover CRLF injection, control-character strip, and the all-control fallback. The lint-suppression allowlist in test/scripts/lint-suppressions.test.ts records the intentional no-control-regex suppress comment.
  • What did NOT change (scope boundary): mimetype passthrough (B-4), caption Bidi/control strip (C-4), inbound media.ts/monitor.ts chain, src/media/sanitize-filename.ts (B-1, blocked on PR fix(media): strip control and bidi characters from outbound filenames #72973), CHANGELOG.md, docs.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

  • Root cause: The document-send branch only called .trim(), which removes leading/trailing whitespace but leaves CR, LF, and other control characters intact anywhere in the string.
  • Missing detection / guardrail: No test for injection payloads in fileName; existing tests passed only clean filenames.
  • Contributing context (if known): fileName propagates verbatim from the inbound WhatsApp documentMessage.fileName field through monitor.tssendOptions.fileName, so any peer can supply arbitrary bytes.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/whatsapp/src/document-filename.test.ts
  • Scenario the test should lock in: (1) CRLF-containing fileName reaches resolveWhatsAppDocumentFileName with CR/LF stripped; (2) C0/DEL control characters stripped, valid chars preserved; (3) all-control filename falls back to MIME-derived name (e.g., "file.pdf" for application/pdf).
  • Why this is the smallest reliable guardrail: The sanitizer is a pure function; injection can be asserted by calling it directly with attacker-controlled inputs and verifying the return value.
  • Existing test that already covers this (if any): None — no prior test exercised control-character inputs.
  • If no new test is added, why not: N/A — 3 tests added.

User-visible / Behavior Changes

Documents sent with filenames containing control characters will have those characters stripped before delivery. Filenames consisting entirely of control characters will fall back to a MIME-derived filename (e.g., "file.pdf" for application/pdf). Clean filenames are unaffected.

Diagram (if applicable)

Before:
[sendOptions.fileName = "evil.pdf\r\nX-Injected: bad"]
  -> .trim()
  -> fileName = "evil.pdf\r\nX-Injected: bad"  (injection survives)

After:
[sendOptions.fileName = "evil.pdf\r\nX-Injected: bad"]
  -> strip [\x00-\x1f\x7f]
  -> .trim()
  -> fileName = "evil.pdfX-Injected: bad"  (CR/LF removed)

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux (Ubuntu 22.04)
  • Runtime/container: Node 22, pnpm
  • Model/provider: N/A
  • Integration/channel (if any): WhatsApp (Baileys)
  • Relevant config (redacted): N/A

Steps

  1. Before fix: call sendMessage(jid, "doc", buffer, "application/pdf", { fileName: "evil.pdf\r\nX-Injected: bad" }).
  2. Observe sendMessage mock receives fileName: "evil.pdf\r\nX-Injected: bad" (injection present).
  3. After fix: same call passes fileName: "evil.pdfX-Injected: bad" (CR/LF stripped).

Expected

fileName passed to Baileys contains no C0 control characters or DEL.

Actual (before fix)

CR and LF bytes survived .trim() in the middle of the string.

Evidence

  • Baileys outbound document payload boundary — real Baileys runtime spy-through (see Real behavior proof section below)
# document-filename.test.ts (6 tests, PR HEAD 1f377fe0ed):
Test Files  1 passed (1)
     Tests  6 passed (6)
  Duration  411ms

# lint-suppressions.test.ts (3 tests):
Test Files  1 passed (1)
     Tests  3 passed (3)

Human Verification (required)

  • Verified scenarios: CRLF strip (middle-of-string), NUL + US + DEL strip (non-printable C0/DEL), all-control fallback to MIME-derived name, clean fileName passthrough (regression).
  • Edge cases checked: \r\n\x00\x1f all-control → "file.pdf" (MIME fallback for application/pdf); "invoice.pdf" unchanged; "a\x00b\x1fc\x7f.pdf""abc.pdf".
  • What you did not verify: live Baileys wire behavior (requires a running WhatsApp session); no E2E or live test run.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: A fileName containing valid text that begins/ends with whitespace (but no control chars) is already trimmed by the old code. The new code strips control chars first, then trims — same trim behavior, narrower bypass window.
    • Mitigation: The regression test "returns plain filename unchanged when no control characters present" passes a clean "document.pdf" and verifies it reaches the sanitizer unchanged.

Real behavior proof

Behavior addressed: WhatsApp outbound document fileName values containing C0 control characters and DEL — including CR, LF, NUL, US, and DEL — are stripped before reaching the Baileys document payload. If the stripped filename becomes empty, the existing MIME-aware fallback is used. Clean filenames are preserved.

Real environment tested: Linux/Ubuntu, Node v22.22.2, pnpm 11.1.0, PR HEAD 1f377fe0ed. PR source modules loaded directly from this branch via tsxextensions/whatsapp/src/inbound/send-api.ts (createWebSendApi) and extensions/whatsapp/src/document-filename.ts (resolveWhatsAppDocumentFileName). The socket is a real Baileys 7.0.0-rc11 WhatsApp Web client (makeWASocket + useMultiFileAuthState), paired via requestPairingCode to a dedicated proof account that owns the recipient number, and the recipient is the same account's own self chat. No mock sock, no fake recorder: a 1-deep sendMessage spy wrapper captures payload.fileName / payload.mimetype and then unconditionally awaits the original Baileys sock.sendMessage bound to the same socket instance, so every captured send is also a real send.

Exact steps or command run after this patch:

From a clean checkout of this branch on a host with pnpm install completed, and with an own WhatsApp account number available for proof-only pairing.

First, create a proof-only auth store outside the repo, mode 0700:

mkdir -p "$HOME/.openclaw/credentials/proof-77114-whatsapp"
chmod 700 "$HOME/.openclaw/credentials/proof-77114-whatsapp"

Then run the proof script interactively. The script connects a real Baileys 7.0.0-rc11 WhatsApp Web socket, requests a pairing code (it handles the restartRequired (515) re-connect after the phone accepts the code), then routes ONE document send through createWebSendApi (the PR-modified boundary). sock.sendMessage is wrapped as a spy that LOGS payload.fileName and ALWAYS delegates to the real Baileys sock.sendMessage. The phone number is read from env, never echoed; the recipient JID and WA message id are not printed and are redacted in the public proof. Enter the printed pairing code on the primary phone (WhatsApp → Linked Devices → Link with phone number instead).

WA_PROOF_PHONE_DIGITS=<digits-only own number> \
WA_PROOF_AUTH_DIR="$HOME/.openclaw/credentials/proof-77114-whatsapp" \
node_modules/.bin/tsx --tsconfig tsconfig.json \
  scripts/proof-77114-baileys-runtime.ts

Evidence after fix:

Output captured on PR HEAD 1f377fe0ed, Node v22.22.2, baileys 7.0.0-rc11, one live Baileys session paired against the proof account. The phone number is never echoed; the recipient JID and WA message id are fully redacted.

connection_opened           : true
real_socket_used            : true (baileys 7.0.0-rc11)
spy_wrapper_used            : true (LOG + always delegate)
delegated_to_original       : true
fake_sock_used              : false (no recorder; spy ALWAYS calls original)
recipient_jid               : <redacted>
payload_keys                : ["document","fileName","caption","mimetype"]
payload_mimetype            : "text/plain"
input_fileName_escaped      : "oc-proof-\r\ninjected\x00\x1f\x7f.txt"
input_fileName_hex          : \x6f\x63\x2d\x70\x72\x6f\x6f\x66\x2d\x0d\x0a\x69\x6e\x6a\x65\x63\x74\x65\x64\x00\x1f\x7f\x2e\x74\x78\x74
actual_payload_fileName     : "oc-proof-injected.txt"
actual_payload_fileName_hex : \x6f\x63\x2d\x70\x72\x6f\x6f\x66\x2d\x69\x6e\x6a\x65\x63\x74\x65\x64\x2e\x74\x78\x74
expected_sanitized_fileName : "oc-proof-injected.txt"
fileName_matches_expected   : true
send_result_exists          : true
send_result_message_id      : <redacted>

Observed result after fix:

The five control bytes present in the input filename hex — \x0d (CR), \x0a (LF), \x00 (NUL), \x1f (US), \x7f (DEL) — are all absent from the payload hex handed to real Baileys sock.sendMessage. resolveWhatsAppDocumentFileName collapsed the dirty filename to "oc-proof-injected.txt" before createWebSendApi constructed the document payload, and the same value reached the real WhatsApp Web socket (the spy wrapper delegated, the socket returned a real message id). For an all-control input, the existing MIME-aware fallback path is exercised by the unit tests in extensions/whatsapp/src/document-filename.test.ts (case "3. all-control → MIME fallback"); the live boundary capture above covers the non-empty injection case, which is the realistic CWE-93 vector.

Phone-side verification also confirmed the delivered WhatsApp document displayed as oc-proof-injected.txt with caption OpenClaw #77114 proof; no phone number, JID, contact list, or message id is included in the public proof.

What was not tested:

  • The other WhatsApp content paths (image / audio / video / mentions / quote / caption) are not exercised by this proof. Caption / mentions sanitization is tracked separately (PR-CANDIDATES C-4).
  • Inbound documentMessage.fileName propagation through media.ts / monitor.ts is observed only indirectly: the inbound surface is what supplies attacker-controlled bytes, and this PR's sanitizer sits at the outbound boundary.
  • The proof socket is short-lived (paired, one send, closed). Long-running session behavior is not exercised.
  • No phone number, full recipient JID, full WA message id, credential, token, or chat-list metadata was logged or captured. The proof-only Baileys auth state lives in a directory outside the repo (mode 0700) and is never committed.

@openclaw-barnacle openclaw-barnacle Bot added channel: whatsapp-web Channel integration: whatsapp-web size: S labels May 4, 2026
@clawsweeper

clawsweeper Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 28, 2026, 12:07 AM ET / 04:07 UTC.

Summary
The PR strips C0 control characters and DEL from WhatsApp outbound document filenames in resolveWhatsAppDocumentFileName, adds regression tests, and records the required lint suppression.

PR surface: Source +3, Tests +53. Total +56 across 3 files.

Reproducibility: yes. Source inspection on current main shows the resolver only trims and the send API forwards the resulting fileName into the Baileys document payload; the PR body also provides before/after Baileys runtime proof for the sanitized path.

Review metrics: none identified.

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

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

Next step before merge

  • [P2] No repair lane is needed; the remaining action is ordinary maintainer review, required checks, and merge gating for the open PR.

Security
Cleared: The diff narrows an outbound WhatsApp document metadata surface and does not add dependencies, scripts, permissions, secrets handling, or new network calls.

Review details

Best possible solution:

Land the narrow helper-level sanitization after required checks; keep broader filename or caption hardening as separately scoped follow-up work rather than expanding this PR.

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

Yes. Source inspection on current main shows the resolver only trims and the send API forwards the resulting fileName into the Baileys document payload; the PR body also provides before/after Baileys runtime proof for the sanitized path.

Is this the best way to solve the issue?

Yes. Centralizing the strip in resolveWhatsAppDocumentFileName is the narrow maintainable fix for both document branches that already use the helper, without changing config, provider routing, or Baileys integration semantics.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 736e04cb9099.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix live Baileys runtime output showing the sanitized filename reaching a real sock.sendMessage, and the latest head only changes the related test coverage.

Label justifications:

  • P2: This is a bounded WhatsApp security hardening fix for outbound document metadata with limited channel-specific blast radius.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes after-fix live Baileys runtime output showing the sanitized filename reaching a real sock.sendMessage, and the latest head only changes the related test coverage.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix live Baileys runtime output showing the sanitized filename reaching a real sock.sendMessage, and the latest head only changes the related test coverage.
Evidence reviewed

PR surface:

Source +3, Tests +53. Total +56 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 1 4 1 +3
Tests 2 53 0 +53
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 57 1 +56

What I checked:

Likely related people:

  • scoootscooob: Commit 16505718e8278e6c8dff0e5227a5cb5a9f7c56df moved the WhatsApp channel implementation, including inbound/send-api.ts, into extensions/whatsapp. (role: introduced current extension send surface; confidence: medium; commits: 16505718e827; files: extensions/whatsapp/src/inbound/send-api.ts, extensions/whatsapp/src/inbound/send-api.test.ts)
  • bobbyt74: Commit cae1d9bc6d6c0e601e3b9ff0f6c2f9e9a1fcaa0d added WhatsApp MIME fallback behavior and tests in the same inbound send API area. (role: adjacent fallback behavior contributor; confidence: medium; commits: cae1d9bc6d6c; files: extensions/whatsapp/src/inbound/send-api.ts, extensions/whatsapp/src/inbound/send-api.test.ts)
  • mcaxtr: The MIME fallback commit records mcaxtr as reviewer/co-author, and the latest PR head commit tightens the DEL regression test on this exact sanitizer surface. (role: recent reviewer and adjacent owner; confidence: high; commits: cae1d9bc6d6c, f419b4809c0c; files: extensions/whatsapp/src/inbound/send-api.ts, extensions/whatsapp/src/document-filename.test.ts)
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.

masatohoshino added a commit to masatohoshino/openclaw that referenced this pull request May 4, 2026
@byungskers

This comment was marked as low quality.

@masatohoshino

Copy link
Copy Markdown
Contributor Author

@byungskers Thanks for the thoughtful review!

I did a quick pass over the WhatsApp filename-like metadata paths, and I agree this is worth tracking separately. A couple of related document filename paths should be covered by the shared media filename sanitization work in #72973, and at least one remaining path looks better suited for an independent follow-up.

I’d still keep this PR scoped to the outbound document fileName boundary covered by the regression tests here. Captions/location fields look semantically different since they flow as message text rather than filename/header-like metadata.

Thanks again — I’ll treat the remaining paths as follow-up candidates rather than blockers for this PR.

@masatohoshino masatohoshino force-pushed the feature/openclaw-whatsapp-document-filename-sanitize branch from c32afd3 to c153925 Compare May 17, 2026 07:19
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 17, 2026
masatohoshino added a commit to masatohoshino/openclaw that referenced this pull request May 17, 2026
@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. impact:security Security boundary, credential, authz, sandbox, or sensitive-data risk. labels May 17, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: supplied External PR includes structured after-fix real behavior proof. labels May 17, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 17, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 17, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 17, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 17, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 17, 2026
@mcaxtr mcaxtr self-assigned this May 28, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 28, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed impact:security Security boundary, credential, authz, sandbox, or sensitive-data risk. labels May 28, 2026
@clawsweeper

clawsweeper Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Neon Diff Drake

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: hums during re-review.
Image traits: location branch lighthouse; accessory rollback rope; palette plum, gold, and soft gray; mood focused; pose pointing at a small proof artifact; shell smooth pearl shell; lighting tiny status-light glow; background gentle dashboard dots.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Neon Diff Drake in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@mcaxtr mcaxtr force-pushed the feature/openclaw-whatsapp-document-filename-sanitize branch from fe3f903 to f419b48 Compare May 28, 2026 03:59
mcaxtr pushed a commit to masatohoshino/openclaw that referenced this pull request May 28, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 28, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 28, 2026
mcaxtr pushed a commit to masatohoshino/openclaw that referenced this pull request May 28, 2026
@mcaxtr mcaxtr force-pushed the feature/openclaw-whatsapp-document-filename-sanitize branch from f419b48 to e5a94fd Compare May 28, 2026 04:11
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 28, 2026
mcaxtr pushed a commit to masatohoshino/openclaw that referenced this pull request May 28, 2026
@mcaxtr mcaxtr force-pushed the feature/openclaw-whatsapp-document-filename-sanitize branch from e5a94fd to f1fdf95 Compare May 28, 2026 04:14
mcaxtr pushed a commit to masatohoshino/openclaw that referenced this pull request May 28, 2026
@mcaxtr mcaxtr force-pushed the feature/openclaw-whatsapp-document-filename-sanitize branch from f1fdf95 to fb6de65 Compare May 28, 2026 04:16
masatohoshino and others added 4 commits May 28, 2026 01:16
Moves the CWE-93 sanitization fix from send-api.ts (inlined pre-rebase)
into resolveWhatsAppDocumentFileName() in document-filename.ts, following
upstream PR openclaw#82851's extraction of that helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Formatter had wrapped the return into multiline form, causing the
eslint-disable-next-line directive to point at `return (` instead of
the regex line — yielding one unused-directive error and one
unsuppressed no-control-regex error in CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mcaxtr mcaxtr force-pushed the feature/openclaw-whatsapp-document-filename-sanitize branch from fb6de65 to 5417a8e Compare May 28, 2026 04:17
@mcaxtr mcaxtr merged commit 313d6ae into openclaw:main May 28, 2026
91 checks passed
@mcaxtr

mcaxtr commented May 28, 2026

Copy link
Copy Markdown
Member

Merged via squash.

Thanks @masatohoshino!

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 28, 2026
…me (openclaw#77114)

Merged via squash.

Prepared head SHA: 5417a8e
Co-authored-by: masatohoshino <246810661+masatohoshino@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
steipete pushed a commit that referenced this pull request May 28, 2026
…me (#77114)

Merged via squash.

Prepared head SHA: 5417a8e
Co-authored-by: masatohoshino <246810661+masatohoshino@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request May 31, 2026
…026.5.28) (#759)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/openclaw/openclaw](https://openclaw.ai) ([source](https://github.com/openclaw/openclaw)) | patch | `2026.5.27` → `2026.5.28` |

---

### Release Notes

<details>
<summary>openclaw/openclaw (ghcr.io/openclaw/openclaw)</summary>

### [`v2026.5.28`](https://github.com/openclaw/openclaw/blob/HEAD/CHANGELOG.md#2026528)

[Compare Source](openclaw/openclaw@v2026.5.27...v2026.5.28)

##### Highlights

- Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. ([#&#8203;87218](openclaw/openclaw#87218), [#&#8203;86875](openclaw/openclaw#86875), [#&#8203;87409](openclaw/openclaw#87409), [#&#8203;87399](openclaw/openclaw#87399), [#&#8203;87375](openclaw/openclaw#87375), [#&#8203;88129](openclaw/openclaw#88129))
- Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. ([#&#8203;73706](openclaw/openclaw#73706), [#&#8203;75670](openclaw/openclaw#75670), [#&#8203;87366](openclaw/openclaw#87366), [#&#8203;87451](openclaw/openclaw#87451), [#&#8203;87334](openclaw/openclaw#87334), [#&#8203;84535](openclaw/openclaw#84535), [#&#8203;82492](openclaw/openclaw#82492), [#&#8203;83304](openclaw/openclaw#83304), [#&#8203;87160](openclaw/openclaw#87160))
- Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. ([#&#8203;87367](openclaw/openclaw#87367), [#&#8203;87531](openclaw/openclaw#87531), [#&#8203;87682](openclaw/openclaw#87682), [#&#8203;88096](openclaw/openclaw#88096), [#&#8203;88105](openclaw/openclaw#88105)) Thanks [@&#8203;ngutman](https://github.com/ngutman) and [@&#8203;BunsDev](https://github.com/BunsDev).
- Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. ([#&#8203;82887](openclaw/openclaw#82887))
- Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. ([#&#8203;87845](openclaw/openclaw#87845), [#&#8203;87890](openclaw/openclaw#87890), [#&#8203;80775](openclaw/openclaw#80775), [#&#8203;84764](openclaw/openclaw#84764), [#&#8203;87751](openclaw/openclaw#87751), [#&#8203;87794](openclaw/openclaw#87794))
- CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy `api_key` auth profiles migrate to canonical form, and restart guidance is actionable. ([#&#8203;87398](openclaw/openclaw#87398), [#&#8203;86281](openclaw/openclaw#86281), [#&#8203;87361](openclaw/openclaw#87361), [#&#8203;88133](openclaw/openclaw#88133), [#&#8203;83655](openclaw/openclaw#83655), [#&#8203;87559](openclaw/openclaw#87559), [#&#8203;88088](openclaw/openclaw#88088), [#&#8203;85924](openclaw/openclaw#85924)) Thanks [@&#8203;vincentkoc](https://github.com/vincentkoc) and [@&#8203;giodl73-repo](https://github.com/giodl73-repo).
- Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. ([#&#8203;86699](openclaw/openclaw#86699))
- Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.

##### Changes

- Status: show active subagent details in status output.
- Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. ([#&#8203;87370](openclaw/openclaw#87370), [#&#8203;87372](openclaw/openclaw#87372)) Thanks [@&#8203;RomneyDa](https://github.com/RomneyDa).
- ClawHub: add plugin display names plus skill verification and trust surfaces. ([#&#8203;87354](openclaw/openclaw#87354), [#&#8203;86699](openclaw/openclaw#86699)) Thanks [@&#8203;thewilloftheshadow](https://github.com/thewilloftheshadow) and [@&#8203;Patrick-Erichsen](https://github.com/Patrick-Erichsen).
- iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. ([#&#8203;87367](openclaw/openclaw#87367), [#&#8203;88096](openclaw/openclaw#88096), [#&#8203;88105](openclaw/openclaw#88105)) Thanks [@&#8203;Solvely-Colin](https://github.com/Solvely-Colin) and [@&#8203;ngutman](https://github.com/ngutman).
- Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. ([#&#8203;87313](openclaw/openclaw#87313), [#&#8203;63050](openclaw/openclaw#63050), [#&#8203;87685](openclaw/openclaw#87685)) Thanks [@&#8203;bdjben](https://github.com/bdjben), [@&#8203;liaoandi](https://github.com/liaoandi), and [@&#8203;thewilloftheshadow](https://github.com/thewilloftheshadow).
- PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. ([#&#8203;87670](openclaw/openclaw#87670), [#&#8203;87751](openclaw/openclaw#87751))
- Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. ([#&#8203;87845](openclaw/openclaw#87845), [#&#8203;87890](openclaw/openclaw#87890), [#&#8203;80775](openclaw/openclaw#80775), [#&#8203;84764](openclaw/openclaw#84764), [#&#8203;87794](openclaw/openclaw#87794)) Thanks [@&#8203;eleqtrizit](https://github.com/eleqtrizit) and [@&#8203;vincentkoc](https://github.com/vincentkoc).
- Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.
- Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.
- Workboard: add agent coordination tools for tracking and handing off active agent work.
- Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. ([#&#8203;85200](openclaw/openclaw#85200))
- Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. ([#&#8203;82823](openclaw/openclaw#82823), [#&#8203;87165](openclaw/openclaw#87165)) Thanks [@&#8203;piersonr](https://github.com/piersonr) and [@&#8203;RomneyDa](https://github.com/RomneyDa).
- Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. ([#&#8203;85572](openclaw/openclaw#85572), [#&#8203;85744](openclaw/openclaw#85744), [#&#8203;86768](openclaw/openclaw#86768))

##### Fixes

- Agents: fall back to local config pruning when the optional `agents delete` Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.
- Tighten phone-control mutation authorization \[AI]. ([#&#8203;87150](openclaw/openclaw#87150)) Thanks [@&#8203;pgondhi987](https://github.com/pgondhi987).
- Clarify directive persistence authorization policy \[AI]. ([#&#8203;86369](openclaw/openclaw#86369)) Thanks [@&#8203;pgondhi987](https://github.com/pgondhi987).
- Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format `skills` command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. ([#&#8203;87218](openclaw/openclaw#87218), [#&#8203;86875](openclaw/openclaw#86875), [#&#8203;86123](openclaw/openclaw#86123), [#&#8203;88129](openclaw/openclaw#88129), [#&#8203;87399](openclaw/openclaw#87399), [#&#8203;87375](openclaw/openclaw#87375), [#&#8203;72574](openclaw/openclaw#72574), [#&#8203;87383](openclaw/openclaw#87383), [#&#8203;87400](openclaw/openclaw#87400), [#&#8203;83022](openclaw/openclaw#83022), [#&#8203;87671](openclaw/openclaw#87671), [#&#8203;87738](openclaw/openclaw#87738), [#&#8203;87747](openclaw/openclaw#87747), [#&#8203;87706](openclaw/openclaw#87706), [#&#8203;87546](openclaw/openclaw#87546), [#&#8203;87541](openclaw/openclaw#87541), [#&#8203;81048](openclaw/openclaw#81048)) Thanks [@&#8203;mbelinky](https://github.com/mbelinky), [@&#8203;Alix-007](https://github.com/Alix-007), [@&#8203;luoyanglang](https://github.com/luoyanglang), [@&#8203;yetval](https://github.com/yetval), [@&#8203;sjf](https://github.com/sjf), [@&#8203;joshavant](https://github.com/joshavant), [@&#8203;benjamin1492](https://github.com/benjamin1492), [@&#8203;c19354837](https://github.com/c19354837), [@&#8203;fuller-stack-dev](https://github.com/fuller-stack-dev), [@&#8203;pfrederiksen](https://github.com/pfrederiksen), and [@&#8203;dodge1218](https://github.com/dodge1218).
- Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.
- Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. ([#&#8203;73706](openclaw/openclaw#73706), [#&#8203;75670](openclaw/openclaw#75670), [#&#8203;87366](openclaw/openclaw#87366), [#&#8203;87451](openclaw/openclaw#87451), [#&#8203;87465](openclaw/openclaw#87465), [#&#8203;87334](openclaw/openclaw#87334), [#&#8203;84535](openclaw/openclaw#84535), [#&#8203;76262](openclaw/openclaw#76262), [#&#8203;83304](openclaw/openclaw#83304), [#&#8203;82492](openclaw/openclaw#82492), [#&#8203;87581](openclaw/openclaw#87581), [#&#8203;77114](openclaw/openclaw#77114), [#&#8203;86426](openclaw/openclaw#86426), [#&#8203;85529](openclaw/openclaw#85529), [#&#8203;87160](openclaw/openclaw#87160)) Thanks [@&#8203;zeroaltitude](https://github.com/zeroaltitude), [@&#8203;lukeboyett](https://github.com/lukeboyett), [@&#8203;jarvis-mns1](https://github.com/jarvis-mns1), [@&#8203;xiaotian](https://github.com/xiaotian), [@&#8203;funmerlin](https://github.com/funmerlin), [@&#8203;joshavant](https://github.com/joshavant), [@&#8203;eleqtrizit](https://github.com/eleqtrizit), [@&#8203;heyitsaamir](https://github.com/heyitsaamir), [@&#8203;amittell](https://github.com/amittell), [@&#8203;lidge-jun](https://github.com/lidge-jun), [@&#8203;liorb-mountapps](https://github.com/liorb-mountapps), [@&#8203;masatohoshino](https://github.com/masatohoshino), [@&#8203;bladin](https://github.com/bladin), and [@&#8203;giodl73-repo](https://github.com/giodl73-repo).
- CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical `api_key` auth profiles, and make doctor restart follow-ups actionable. ([#&#8203;87398](openclaw/openclaw#87398), [#&#8203;86281](openclaw/openclaw#86281), [#&#8203;87361](openclaw/openclaw#87361), [#&#8203;88133](openclaw/openclaw#88133), [#&#8203;83655](openclaw/openclaw#83655), [#&#8203;87559](openclaw/openclaw#87559), [#&#8203;87719](openclaw/openclaw#87719), [#&#8203;88088](openclaw/openclaw#88088), [#&#8203;85924](openclaw/openclaw#85924), [#&#8203;84362](openclaw/openclaw#84362)) Thanks [@&#8203;Patrick-Erichsen](https://github.com/Patrick-Erichsen), [@&#8203;samzong](https://github.com/samzong), [@&#8203;giodl73-repo](https://github.com/giodl73-repo), [@&#8203;alkor2000](https://github.com/alkor2000), [@&#8203;mmaps](https://github.com/mmaps), [@&#8203;nxmxbbd](https://github.com/nxmxbbd), and [@&#8203;vincentkoc](https://github.com/vincentkoc).
- Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. ([#&#8203;87810](openclaw/openclaw#87810), [#&#8203;87833](openclaw/openclaw#87833), [#&#8203;75089](openclaw/openclaw#75089)) Thanks [@&#8203;joshavant](https://github.com/joshavant) and [@&#8203;litang9](https://github.com/litang9).
- Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 `no_proxy` entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. ([#&#8203;87883](openclaw/openclaw#87883)) Thanks [@&#8203;zhangguiping-xydt](https://github.com/zhangguiping-xydt).
- Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.
- Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. ([#&#8203;82887](openclaw/openclaw#82887)) Thanks [@&#8203;chen-zhang-cs-code](https://github.com/chen-zhang-cs-code).
- Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. ([#&#8203;87683](openclaw/openclaw#87683))
- WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. ([#&#8203;82492](openclaw/openclaw#82492)) Thanks [@&#8203;lidge-jun](https://github.com/lidge-jun).
- Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.
- Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. ([#&#8203;87476](openclaw/openclaw#87476), [#&#8203;87423](openclaw/openclaw#87423))
- Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. ([#&#8203;86611](openclaw/openclaw#86611)) Thanks [@&#8203;ferminquant](https://github.com/ferminquant).
- Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek `reasoning_content` replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. ([#&#8203;87593](openclaw/openclaw#87593), [#&#8203;87493](openclaw/openclaw#87493), [#&#8203;80775](openclaw/openclaw#80775), [#&#8203;84764](openclaw/openclaw#84764)) Thanks [@&#8203;Pluviobyte](https://github.com/Pluviobyte) and [@&#8203;eleqtrizit](https://github.com/eleqtrizit).
- Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. ([#&#8203;87523](openclaw/openclaw#87523), [#&#8203;87982](openclaw/openclaw#87982))
- File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.
- Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. ([#&#8203;87760](openclaw/openclaw#87760))
- Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. ([#&#8203;87647](openclaw/openclaw#87647), [#&#8203;87477](openclaw/openclaw#87477)) Thanks [@&#8203;rohitjavvadi](https://github.com/rohitjavvadi) and [@&#8203;vincentkoc](https://github.com/vincentkoc).
- Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. ([#&#8203;87839](openclaw/openclaw#87839))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/759
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
…me (openclaw#77114)

Merged via squash.

Prepared head SHA: 5417a8e
Co-authored-by: masatohoshino <246810661+masatohoshino@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
…me (openclaw#77114)

Merged via squash.

Prepared head SHA: 5417a8e
Co-authored-by: masatohoshino <246810661+masatohoshino@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: whatsapp-web Channel integration: whatsapp-web P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S 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.

3 participants