BlueBubbles: webhook auth for SecretRef passwords (#76369)#76410
BlueBubbles: webhook auth for SecretRef passwords (#76369)#76410neeravmakwana wants to merge 1 commit intoopenclaw:mainfrom
Conversation
…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>
|
Codex review: needs maintainer review before merge. Summary Reproducibility: yes. from source inspection. A BlueBubbles webhook target with Next step before merge Security Review detailsBest 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 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:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 5f5e0a3633c2. |
|
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. |
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
isMatchpath usedaccount.config.password?.trim(), assuming a string.SecretRefis an object without.trim, which threwTypeError: ... trim is not a functionand 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
monitor.ts): After extracting the presented token (guid/query/header/Authorization), match it withnormalizeSecretInputString(password)when the password is an inline non-empty string; otherwise resolvepasswordviaresolveConfiguredSecretInputString(same secret pipeline used elsewhere).webhook-targets.ts): WhenresolveSingleWebhookTargetAsyncevaluatesisMatch, if the matcher returns a plainboolean, use it synchronously; only await when it returns aPromise<boolean>. Combined with forwardingparams.isMatchdirectly fromresolveWebhookTargetWithAuthOrReject, this avoids an extra async wrapper hop.monitor.webhook-auth.test.ts): Assert plaintext passwords do not callresolveConfiguredSecretInputString; SecretRef-shaped config drives one resolver invocation and succeeds when the mocked resolved value matches the presented webhook token (with#ts-expect-errornoting runtime SecretRef merges vs the narrow bundledBlueBubblesAccountConfigtypings).monitor.webhook.test-helpers.ts): Emit mock request bodies onsetImmediateso 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
safeEqualSecret/safeEqualAuthTokenparity with prior behavior once the resolved password string is obtained.resolveConfiguredSecretInputString): exec/file/env refs still obey gateway policy and provider configs.WEBHOOK_RATE_LIMIT_DEFAULTS), in-flight guards, SSRF allowances, and Trusted proxy / loopback webhook rules are untouched.Tests run
Out of scope / follow-ups
BlueBubblesAccountConfig.passwordtoSecretInputin typings ripples multiple call sites; left as a typings follow-up. Runtime already accepts refs from merged gateway config.AI-assisted checklist (CONTRIBUTING)
pnpm check:changed, targeted Vitest).Fixes #76369