Skip to content

bluebubbles: tighten SSRF guard on API fetches (bypass via undefined SsrFPolicy) #67752

@omarshahine

Description

@omarshahine

Summary

Aisle security analysis on #67510 flagged (Medium / CWE-918) that several BlueBubbles fetch call-sites currently pass undefined for ssrfPolicy to explicitly take the non-SSRF fallback path in blueBubblesFetchWithTimeout. That path intentionally skips fetchWithSsrFGuard to support self-hosted deployments on localhost — but in doing so it also drops DNS pinning, private-IP blocking, and redirect controls for any request to the configured BlueBubbles baseUrl.

The design tradeoff was deliberate (localhost BB is the common case, and default SSRF policy blocks private IPs), but the Aisle report correctly notes that a safer pattern exists and is already used in downloadBlueBubblesAttachment:

ssrfPolicy: allowPrivateNetwork
  ? { allowPrivateNetwork: true }
  : trustedHostname && (allowPrivateNetworkConfig !== false || !trustedHostnameIsPrivate)
    ? { allowedHostnames: [trustedHostname] }
    : undefined,

This keeps SSRF protections scoped to only the configured hostname, which is almost always what the user actually wants — localhost works, but redirects/rebinding to anything else still get blocked.

Call-sites to migrate

  • extensions/bluebubbles/src/attachments.tsblueBubblesPolicy() helper + its caller sendBlueBubblesAttachment (outbound path)
  • extensions/bluebubbles/src/monitor-processing.tsblueBubblesPolicy() helper used by fetchBlueBubblesParticipantsForInboundMessage and the attachment retry path (fetchBlueBubblesMessageAttachments)
  • extensions/bluebubbles/src/send.ts, chat.ts, probe.ts, reactions.ts, multipart.ts, catchup.ts — each has their own copy of the blueBubblesPolicy pattern, all currently routing localhost through the unguarded fallback in one form or another.

Worth a single pass that centralises a shared resolveBlueBubblesSsrFPolicy({ baseUrl, allowPrivateNetwork }) helper returning { allowedHostnames: [hostname] } by default, { allowPrivateNetwork: true } when explicitly opted in.

Context

Acceptance

  • All BlueBubbles fetch call-sites use a policy that scopes SSRF to the configured baseUrl hostname, not undefined.
  • Localhost / same-host / private-IP deployments continue to work without dangerouslyAllowPrivateNetwork: true when the user has configured the server to that host.
  • lint:tmp:no-raw-channel-fetch stays clean (no new raw-fetch call-sites needed).

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintainerMaintainer-authored PR

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions