Skip to content

fix(gateway): reject empty BlueBubbles webhook token + refuse unauthenticated non-loopback bind - #36862

Closed
dhyabi2 wants to merge 1 commit into
NousResearch:mainfrom
dhyabi2:fix/bluebubbles-webhook-auth
Closed

fix(gateway): reject empty BlueBubbles webhook token + refuse unauthenticated non-loopback bind#36862
dhyabi2 wants to merge 1 commit into
NousResearch:mainfrom
dhyabi2:fix/bluebubbles-webhook-auth

Conversation

@dhyabi2

@dhyabi2 dhyabi2 commented Jun 1, 2026

Copy link
Copy Markdown

What & why

The BlueBubbles webhook builds its auth token from an or-chain over five request-supplied sources and compares it with token != self.password. self.password defaults to "" when BLUEBUBBLES_PASSWORD is unset, and supplying any source as an empty value makes the chain return "", so "" != "" is False → the request authenticates. When the adapter is network-exposed without a password, an attacker can forge inbound iMessage webhook events.

Reproduction (empty-valued header bypasses auth when no password is set):

POST /bluebubbles-webhook HTTP/1.1
Host: target:8645
x-bluebubbles-guid:

{}

The fix

  • Reject empty tokens and use hmac.compare_digest for constant-time comparison: require both token and self.password to be non-empty.
  • Refuse to start when bound to a non-loopback host (e.g. 0.0.0.0) without a password set — mirroring the existing guard in gateway/platforms/api_server.py.

How to test

# empty token / empty password -> 401 (was: authenticated)
# missing token                -> 401 (unchanged)
# correct token                -> 200 (unchanged)

Default 127.0.0.1 bind without a password still starts (loopback only); a 0.0.0.0 bind without a password now raises at startup instead of exposing an open webhook.

Platforms

Logic-only change in gateway/platforms/bluebubbles.py.

Fixes #36849. Reported privately as part of GHSA-gmqw-rqrf-c48w (closed 2026-05-14 without a fix); still reproducible on main.

…henticated non-loopback bind

The webhook auth built the token from an or-chain over five request-supplied
sources and compared it with 'token != self.password'. self.password
defaults to '' when BLUEBUBBLES_PASSWORD is unset, and supplying any source
as an empty value makes the chain return '', so '' == '' authenticated the
request. Reject empty tokens, use hmac.compare_digest for constant-time
comparison, and refuse to start when bound to a non-loopback host without a
password (mirrors the api_server.py guard).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dhyabi2

dhyabi2 commented Jun 1, 2026

Copy link
Copy Markdown
Author

Withdrawing this — on closer analysis the reported bypass is not reachable.

BlueBubblesAdapter.connect() refuses to start the webhook unless a password is set:

# gateway/platforms/bluebubbles.py:160-165
async def connect(self) -> bool:
    if not self.server_url or not self.password:
        logger.error("[bluebubbles] BLUEBUBBLES_SERVER_URL and BLUEBUBBLES_PASSWORD are required")
        return False

The webhook is bound only inside connect() (after this guard), so self.password is never empty while the endpoint is live. The empty-token equality ("" == self.password) therefore can never authenticate — the precondition the report relied on (BLUEBUBBLES_PASSWORD unset) cannot occur. This guard was also present at the originally-reported commit, so the finding was not valid there either. Apologies for the noise.

(The other three reports — #36846, #36847, #36848 — are unaffected and remain reproducible.)

@dhyabi2 dhyabi2 closed this Jun 1, 2026
@alt-glitch alt-glitch added type/security Security vulnerability or hardening P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery area/auth Authentication, OAuth, credential pools labels Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: BlueBubbles webhook auth bypass via empty-valued token header when BLUEBUBBLES_PASSWORD is unset

2 participants