openclaw - ✅(Solved) Fix BlueBubbles: move `?password=` URL auth to header-based auth across all BB API calls [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#66869Fetched 2026-04-16 06:37:33
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Assignees
Timeline (top)
assigned ×1cross-referenced ×1labeled ×1renamed ×1

Error Message

  • Error messages / stack traces that include the URL
  • OR at minimum, redact the password in any URL logging / error-path output and fail-closed on any HTTP redirect
  1. If header auth isn't available upstream: at least add URL redaction in blueBubblesFetchWithTimeout error paths and anywhere URLs get logged, and add a runtime check that rejects redirects.

Root Cause

Aisle's security scan flags this as CWE-598 (sensitive data exposure in URL) because query-string credentials can be captured by:

  • HTTP access logs on the BB Server, reverse proxies, load balancers
  • Monitoring / tracing systems that record full URLs
  • Error messages / stack traces that include the URL
  • Referer header propagation in some stacks

Fix Action

Fixed

PR fix notes

PR #66857: feat(bluebubbles): replay missed webhook messages after gateway restart (#66721)

Description (problem / solution / changelog)

Summary

Fixes #66721. Adds an in-process startup catchup pass to the BlueBubbles channel that queries BB Server for messages delivered while the gateway was unreachable and replays them through the existing processMessage pipeline.

The hole this closes: BB Server's WebhookService is fire-and-forget on POST failure (no retries) and BB's MessagePoller only re-fires webhooks on BB-side reconnection events (Messages.app / APNs), not on webhook-receiver recovery. Messages delivered while the gateway was down, restarting, or wedged were permanently lost — verified with a controlled experiment on macOS.

This PR supersedes #66853 (which was the stacked follow-up to #66760 / dedupe PR #66816). Same diff, collapsed to a single commit for cleaner review. History of review feedback is preserved in the superseded PR trail; all P1 and P2 findings from Greptile / Codex / Aisle were addressed in-branch before this squash.

Design

  • New extensions/bluebubbles/src/catchup.ts:
    • fetchBlueBubblesMessagesSince(sinceMs, limit, opts) calls /api/v1/message/query with {after, sort:"ASC", with:["chat","chat.participants","attachment"]} so replays carry the same shape normalizeWebhookMessage already handles on live dispatch.
    • loadBlueBubblesCatchupCursor / saveBlueBubblesCatchupCursor persist a single {lastSeenMs, updatedAt} per account under <stateDir>/bluebubbles/catchup/<accountId>__<hash>.json, using the plugin-sdk's atomic JSON helpers. File layout mirrors the inbound-dedupe store from #66816, and the resolver is the canonical openclaw/plugin-sdk/state-paths.resolveStateDir (same helper dedupe uses) so the two stores share a single root.
    • runBlueBubblesCatchup(target) orchestrates: clamp config, fetch, filter isFromMe and pre-cursor records, dispatch to processMessage, advance cursor.
  • Modified monitor.ts: fire catchup as a background task after webhook target registers; errors are logged but never block the channel-ready signal.
  • Modified config-schema.ts: new optional catchup block (enabled, maxAgeMinutes, perRunLimit, firstRunLookbackMinutes); defaults on with 2h lookback / 50 msg cap / 30-min first-run lookback.
  • Modified accounts.ts: adds catchup to the account-merge nestedObjectKeys list so per-account overrides deep-merge on top of channel-level defaults, mirroring the existing network precedent.

Why this approach

The fix mirrors a workspace-level shell script that's been running on a real OpenClaw install for ~4 weeks (~100 LoC of bash + python doing the same query/filter/POST flow). Porting it into the BB channel itself means every install gets recovery for free, calls processMessage directly (no re-POST hop), and benefits from #66816's persistent dedupe automatically.

Safety

  • Goes through the same processMessage path webhooks use, so auth, allowlist, pairing, and downstream agent dispatch all apply unchanged.
  • Dedupes against #66816's persistent inbound GUID cache: a webhook delivery that already succeeded cannot be reprocessed by catchup.
  • Never dispatches isFromMe records (double-checked before and after normalization) so the agent's own sends cannot enter the inbound path.
  • Catchup runs once per gateway startup and does NOT skip on rapid restarts — skipping would permanently lose any messages that arrived during the brief downtime between the two startups.
  • Cursor only advances to nowMs on fully-successful runs. On processMessage failure, the cursor is held just before the earliest failure timestamp so the next run retries from there. On truncation (fetchedCount === perRunLimit), the cursor advances only to the last-fetched timestamp so the next gateway startup picks up the unfetched tail.
  • A future-dated cursor (NTP rollback, manual clock adjust) is treated as unusable and falls through to the firstRunLookback path; the cursor is repaired at the end of the run.
  • First-run lookback clamped to the maxAge ceiling so maxAgeMinutes: 5, firstRunLookbackMinutes: 30 cannot exceed the operator's stated cap.
  • Hard ceilings: 12h max lookback, 500 messages per run.
  • Loud WARNING emitted when fetchedCount hits perRunLimit so operators know a single startup didn't drain the full backlog.

Validation

Automated

  • New scoped tests in extensions/bluebubbles/src/catchup.test.ts (21 cases): cursor round-trip, per-account scoping, filesystem-unsafe account IDs, firstRunLookback default and maxAge clamp, enabled: false, rapid-restart-still-runs, isFromMe filter (pre- and post-normalization), query-failure-preserves-cursor, per-message failure isolation, held-cursor-on-retryable-failure, clamp-to-prior-cursor, future-cursor recovery, pre-cursor defense-in-depth, perRunLimit warn / no-warn, and truncation-cursor advances only to page boundary.
  • Full BlueBubbles suite passes: 410/410.
  • pnpm check green (madge, tsgo, oxlint, webhook-auth-body-order, no-pairing-store-group, pairing-account-scope).

Live end-to-end (macOS, BB Server 1.9.x, 2026-04-14)

Repeating the original repro from #66721's issue body with the new in-process catchup:

  1. Stopped gateway cleanly. Verified port refused, no process.
  2. Sent 3 distinct iMessages from a second device. BB-server log shows all 3 dispatches failed with connect ECONNREFUSED 127.0.0.1:18789 and never retried.
  3. Started gateway. Webhook target registered; catchup fired in the background.
  4. Gateway log:
    [bluebubbles] [default] BlueBubbles catchup:
      replayed=3 skipped_fromMe=0 skipped_preCursor=0 failed=0 fetched=3 window_ms=517184
  5. All 3 messages produced agent replies delivered back via BB outbound. Persistent cursor file appeared at ~/.openclaw/bluebubbles/catchup/<accountId>__<hash>.json. Subsequent gateway restart with no new inbound activity logged replayed=0 fetched=0 (no-op).

Test plan

  • pnpm test extensions/bluebubbles/src/catchup.test.ts — 21/21
  • pnpm test extensions/bluebubbles/ — 410/410
  • pnpm check — green
  • Live macOS end-to-end repro
  • Maintainer review

History (for reviewer context)

This PR carries ~11 hours of iterative bot review that happened on the prior PRs (#66760 → #66853). Squashing here for clean review; the findings addressed were:

  • Greptile P2 — align state-dir with canonical SDK resolver; warn on perRunLimit truncation
  • Codex P1 — hold cursor on retryable processMessage failures
  • Codex P1 — always run catchup on startup (no min-interval skip)
  • Codex P1 — keep cursor behind unfetched pages when perRunLimit is hit
  • Codex P2 — clamp first-run window to maxAge
  • Codex P2 — deep-merge catchup overrides at account level
  • Codex P2 — treat future-dated cursor as unusable
  • Codex P2 — clock-skew gate precondition (later obviated by removing the gate)
  • Aisle — 2 of 5 findings apply (password-in-URL and OPENCLAW_STATE_DIR symlink); both are cross-cutting BB-plugin patterns best addressed in separate PRs against the SDK/plugin conventions. Other 3 Aisle findings were in files this PR doesn't touch (stale-SHA scan from pre-rebase).

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/bluebubbles/src/accounts.ts (modified, +1/-1)
  • extensions/bluebubbles/src/catchup.test.ts (added, +621/-0)
  • extensions/bluebubbles/src/catchup.ts (added, +430/-0)
  • extensions/bluebubbles/src/config-schema.ts (modified, +15/-0)
  • extensions/bluebubbles/src/monitor.ts (modified, +15/-2)
RAW_BUFFERClick to expand / collapse

Problem

The BlueBubbles plugin authenticates to BB Server by embedding the API password as a query-string parameter via buildBlueBubblesApiUrl({..., password}). This is done consistently across the plugin:

  • extensions/bluebubbles/src/history.ts/api/v1/chat/.../messages?password=...
  • extensions/bluebubbles/src/probe.ts/api/v1/server/info?password=...
  • extensions/bluebubbles/src/send.ts/api/v1/message/...?password=...
  • extensions/bluebubbles/src/catchup.ts/api/v1/message/query?password=... (recent, landed via #66857)

Aisle's security scan flags this as CWE-598 (sensitive data exposure in URL) because query-string credentials can be captured by:

  • HTTP access logs on the BB Server, reverse proxies, load balancers
  • Monitoring / tracing systems that record full URLs
  • Error messages / stack traces that include the URL
  • Referer header propagation in some stacks

Scope

This is a cross-cutting plugin concern, not specific to any single code path. Fixing only one call site (e.g., catchup) would be inconsistent. The proper fix updates buildBlueBubblesApiUrl to stop emitting ?password=<secret> and instead:

  • Use an Authorization header (if BB Server supports Bearer <password> or equivalent auth scheme)
  • OR move the password into a POST body field for endpoints that accept one
  • OR at minimum, redact the password in any URL logging / error-path output and fail-closed on any HTTP redirect

Implementation direction

  1. Audit BB Server's API documentation to identify which auth schemes it supports besides ?password= (BB Server currently supports password query param as its primary auth mechanism per its docs; a header-based scheme would require an upstream PR to the BB Server itself OR a POST-body compromise for POST endpoints).
  2. If header auth isn't available upstream: at least add URL redaction in blueBubblesFetchWithTimeout error paths and anywhere URLs get logged, and add a runtime check that rejects redirects.
  3. If header auth is available: add an opt-in config to buildBlueBubblesApiUrl + update every call site under extensions/bluebubbles/src/.

Related

  • Aisle finding #1 on PR #66857 (catchup) — deferred here
  • Aisle finding #1 on PR #66760 (prior catchup PR, closed) — same finding, same deferral
  • extensions/bluebubbles/src/types.ts — where buildBlueBubblesApiUrl is defined

extent analysis

TL;DR

Update the buildBlueBubblesApiUrl function to use an Authorization header or move the password into a POST body field to avoid exposing sensitive data in URLs.

Guidance

  • Audit the BB Server's API documentation to determine the supported authentication schemes and identify the best approach for updating the buildBlueBubblesApiUrl function.
  • Consider adding URL redaction in error paths and logging to minimize the exposure of sensitive data, and implement a runtime check to reject HTTP redirects.
  • If header-based authentication is available, add an opt-in config to buildBlueBubblesApiUrl and update all call sites to use the new authentication method.
  • Review the extensions/bluebubbles/src/types.ts file to understand the current implementation of buildBlueBubblesApiUrl and plan the necessary changes.

Example

No code snippet is provided as the issue does not contain sufficient information to create a specific example.

Notes

The solution may require an upstream PR to the BB Server to support header-based authentication. The current implementation of buildBlueBubblesApiUrl and the BB Server's API documentation will guide the choice of solution.

Recommendation

Apply a workaround by adding URL redaction in error paths and logging, and implement a runtime check to reject HTTP redirects, as this is a more immediate and feasible solution given the current constraints.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING