Skip to content

BlueBubbles: webhook auth for SecretRef passwords (#76369)#76410

Closed
neeravmakwana wants to merge 1 commit intoopenclaw:mainfrom
neeravmakwana:fix/bluebubbles-webhook-secretref-76369
Closed

BlueBubbles: webhook auth for SecretRef passwords (#76369)#76410
neeravmakwana wants to merge 1 commit intoopenclaw:mainfrom
neeravmakwana:fix/bluebubbles-webhook-secretref-76369

Conversation

@neeravmakwana
Copy link
Copy Markdown
Contributor

@neeravmakwana neeravmakwana commented May 3, 2026

Summary

Fix inbound BlueBubbles webhook authentication when channels.bluebubbles.password (or account-scoped password) is configured as a SecretRef instead of an inline string. Resolves #76369.

Root cause

The webhook isMatch path used account.config.password?.trim(), assuming a string. SecretRef is an object without .trim, which threw TypeError: ... trim is not a function and caused the gateway to reject every POST (“plugin http route failed”).

Outbound paths already resolve secrets via the shared gateway resolver; webhook auth omitted that coercion.

What changed

  • BlueBubbles (monitor.ts): After extracting the presented token (guid/query/header/Authorization), match it with normalizeSecretInputString(password) when the password is an inline non-empty string; otherwise resolve password via resolveConfiguredSecretInputString (same secret pipeline used elsewhere).
  • Plugin SDK (webhook-targets.ts): When resolveSingleWebhookTargetAsync evaluates isMatch, if the matcher returns a plain boolean, use it synchronously; only await when it returns a Promise<boolean>. Combined with forwarding params.isMatch directly from resolveWebhookTargetWithAuthOrReject, this avoids an extra async wrapper hop.
  • Tests (monitor.webhook-auth.test.ts): Assert plaintext passwords do not call resolveConfiguredSecretInputString; SecretRef-shaped config drives one resolver invocation and succeeds when the mocked resolved value matches the presented webhook token (with #ts-expect-error noting runtime SecretRef merges vs the narrow bundled BlueBubblesAccountConfig typings).
  • Test harness (monitor.webhook.test-helpers.ts): Emit mock request bodies on setImmediate so simulated POST bodies arrive after microtasks servicing async auth completion (same ordering as slow real HTTP adapters). Prevents flaky hangs when webhook auth awaits I/O-backed secret resolution.

Why this fix is safe

  • No weakening of auth semantics: Comparisons remain constant-time via existing safeEqualSecret/safeEqualAuthToken parity with prior behavior once the resolved password string is obtained.
  • Same secret resolution semantics as outbound and other bundled BlueBubbles call sites (resolveConfiguredSecretInputString): exec/file/env refs still obey gateway policy and provider configs.
  • Explicitly unchanged security/runtime posture:
    • Gateway plugin HTTP routing, rate limiting (WEBHOOK_RATE_LIMIT_DEFAULTS), in-flight guards, SSRF allowances, and Trusted proxy / loopback webhook rules are untouched.
    • BlueBubbles API client SSRF/cache behavior unchanged.
    • No new logging of raw secrets beyond existing masked query logging.

Tests run

git diff --check
pnpm exec vitest run src/plugin-sdk/webhook-targets.test.ts --pool=forks --maxWorkers=1
pnpm exec vitest run --config test/vitest/vitest.extension-bluebubbles.config.ts \
  extensions/bluebubbles/src/monitor.webhook-auth.test.ts \
  --pool=threads --maxWorkers=1
pnpm check:changed

Out of scope / follow-ups

AI-assisted checklist (CONTRIBUTING)

  • Mark as AI-assisted in the PR description (this note).
  • Testing noted above (pnpm check:changed, targeted Vitest).
  • Changes understood; production behavior is coercion + resolver parity for webhook tokens only.

Fixes #76369

…aw#76369)

Webhook auth assumed string passwords and called .trim(); SecretRef objects
crash the HTTP route handler. Normalize inline passwords and resolve refs
via the gateway secret resolver, matching outbound BlueBubbles usage.

Treat synchronous boolean webhook target matches without awaiting promises in
resolveSingleWebhookTargetAsync; defer mock HTTP bodies with setImmediate in
tests so async auth reliably attaches listeners.

Fixes openclaw#76369.

Co-authored-by: Cursor <cursoragent@cursor.com>
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 3, 2026

Codex review: needs maintainer review before merge.

Summary
The PR changes BlueBubbles webhook auth to resolve SecretRef-backed passwords asynchronously, re-exports the async webhook matcher, adds focused regression coverage and a changelog entry, and adjusts the webhook test request helper timing.

Reproducibility: yes. from source inspection. A BlueBubbles webhook target with password preserved as a SecretRef object reaches target.account.config.password?.trim() on current main, while schema and docs allow that SecretRef-shaped value.

Next step before merge
The remaining action is maintainer review of a draft/unmergeable PR and issue-closing scope, not a narrow automated repair job.

Security
Cleared: The diff changes secret-backed webhook auth but reuses the existing SecretRef resolver, keeps token comparison in the existing path, and adds no dependency, workflow, permission, or raw-secret logging changes.

Review details

Best possible solution:

Land a ready, rebased version of the webhook SecretRef fix, and either split/track the catchup SecretRef symptom separately or adjust the closing language so the broader linked report is not closed prematurely.

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

Yes, from source inspection. A BlueBubbles webhook target with password preserved as a SecretRef object reaches target.account.config.password?.trim() on current main, while schema and docs allow that SecretRef-shaped value.

Is this the best way to solve the issue?

Yes for the webhook-auth bug. The PR uses the existing gateway SecretRef resolver and preserves the existing constant-time comparison path; the safer maintainer adjustment is issue-scope handling for the separate catchup symptom.

Acceptance criteria:

  • pnpm test extensions/bluebubbles/src/monitor.webhook-auth.test.ts
  • pnpm test extensions/bluebubbles
  • pnpm check:changed

What I checked:

Likely related people:

  • Peter Steinberger: Path history shows the most BlueBubbles monitor touches and most Plugin SDK webhook-targets touches, including webhook auth matching and request lifecycle refactors. (role: recent maintainer and SDK/webhook owner; confidence: high; commits: 283029bdea23, 4b61779a463f, 1c9deeda97ce; files: extensions/bluebubbles/src/monitor.ts, src/plugin-sdk/webhook-targets.ts)
  • Vincent Koc: Current blame for the webhook auth block points to this author, and nearby history includes the BlueBubbles webhook ingress seam split. (role: current-line and webhook-ingress adjacent maintainer; confidence: medium; commits: bcfa5bc32b78, 688eb8435bc5; files: extensions/bluebubbles/src/monitor.ts, extensions/bluebubbles/src/webhook-ingress.ts, src/plugin-sdk/webhook-targets.ts)
  • Omar Shahine: Recent merged BlueBubbles monitor history includes inbound webhook attachment handling and replay/catchup work, which is relevant because the linked issue also mentions a catchup SecretRef symptom. (role: recent BlueBubbles inbound/catchup feature-history owner; confidence: medium; commits: 77d9fd693f18, 6f1d321aabab; files: extensions/bluebubbles/src/monitor.ts, extensions/bluebubbles/src/catchup.ts)

Remaining risk / open question:

  • The linked issue also reports a BlueBubbles catchup SecretRef startup error, and this PR explicitly leaves that path out of scope while using closing syntax for the issue.
  • This read-only pass did not run the PR tests or changed gate; the PR body lists targeted Vitest runs and pnpm check:changed, but they were not independently verified here.
  • The PR is draft and currently unmergeable per the provided metadata, so it needs normal maintainer handling before it can land.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 5f5e0a3633c2.

@joshavant
Copy link
Copy Markdown
Contributor

Thanks @neeravmakwana for the patch. The merged fix in #76449 covers BlueBubbles webhook SecretRef passwords through the shared SecretInput handling and the broader external channel SecretRef resolution path. Closing this PR as superseded by the merged fix.

@joshavant joshavant closed this May 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: bluebubbles Channel integration: bluebubbles size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: @openclaw/bluebubbles 2026.5.2 webhook auth crashes on SecretRef password — TypeError in monitor.ts

2 participants