Skip to content

Allow WebFinger discovery for localhost/private hosts by default - #1386

Merged
raucao merged 9 commits into
masterfrom
bugfix/1384-localhost_discovery
May 27, 2026
Merged

Allow WebFinger discovery for localhost/private hosts by default#1386
raucao merged 9 commits into
masterfrom
bugfix/1384-localhost_discovery

Conversation

@silverbucket

@silverbucket silverbucket commented Apr 27, 2026

Copy link
Copy Markdown
Member

Problem

rs.connect("user@localhost:8000") (and any address whose host resolves to a localhost / private IP) fails immediately with WebFingerError: private or internal addresses are not allowed, before any HTTP request is made.

This is a regression introduced by the webfinger.js v3 upgrade in #1370 (commit 490b5f7) and ships in 2.0.0-beta.9. webfinger.js v3 added an allow_private_addresses config option that defaults to false, and WebFinger#resolveAndValidateHost now throws on any host matching its private/localhost regex before attempting the WebFinger lookup.

That breaks:

  • Local development against any RS server on localhost.
  • Self-hosted users running their RS server on a private LAN address (192.168.x.x, 10.x.x.x, etc.).
  • E2E test suites that drive the real OAuth flow against a Dockerized RS server (which is how we hit it — see silverbucket/inbox-rs#105).

Fix

The SSRF protection makes sense for server-side webfinger callers (the original concern in silverbucket/webfinger.js#65), but remoteStorage.js runs in browsers, where cross-origin requests are already gated by the same-origin policy / CORS — the flag's threat model doesn't apply there and only blocks legitimate localhost / LAN development.

This PR takes option 2 from the issue: a new discovery config object, defaulting to true so beta.9's behaviour is restored, with non-browser embedders able to opt back into the SSRF guard.

// Browser apps (default): localhost / LAN discovery works
const remoteStorage = new RemoteStorage();

// Non-browser embedder that wants the SSRF guard back
const remoteStorage = new RemoteStorage({
  discovery: {
    allowPrivateAddresses: false
  }
});

Breaking changes

  • discoveryTimeout (a flat top-level constructor option added in beta.9) has
    been replaced by discovery.timeout inside the new discovery config object.
    Update any existing usage:

    // before
    new RemoteStorage({ discoveryTimeout: 10000 });
    
    // after
    new RemoteStorage({ discovery: { timeout: 10000 } });

Closes #1384.

webfinger.js v3 added an `allow_private_addresses` config option that
defaults to `false`, so `WebFinger#resolveAndValidateHost` started
throwing on any localhost / private-IP address before any HTTP request
went out. That broke `rs.connect("user@localhost:8000")` and any
self-hosted setup on a private LAN address since `2.0.0-beta.9`.

The SSRF guard makes sense for server-side webfinger callers, but
remoteStorage.js runs in browsers, where cross-origin requests are
already gated by the same-origin policy / CORS. The flag's threat
model doesn't apply there and only blocks legitimate localhost
development.

Add a `discoveryAllowPrivateAddresses` config option that defaults to
`true` (restoring the pre-beta.9 behaviour) and forwards to
webfinger.js. Non-browser embedders that want the SSRF guard back can
opt out via `new RemoteStorage({ discoveryAllowPrivateAddresses: false })`.
Add regression tests covering both paths and document the option in
the `RemoteStorage` constructor docs.
@silverbucket
silverbucket force-pushed the bugfix/1384-localhost_discovery branch from 8fed77b to 8b572e6 Compare April 27, 2026 19:45
@silverbucket silverbucket changed the title Allow localhost / private addresses in Discover (fixes #1384) Fix WebFinger discovery for localhost / private hosts (fixes #1384) Apr 27, 2026
@silverbucket silverbucket self-assigned this Apr 27, 2026
Updated comment for WebFinger discovery setting.
@silverbucket
silverbucket marked this pull request as ready for review April 27, 2026 20:01
@silverbucket silverbucket changed the title Fix WebFinger discovery for localhost / private hosts (fixes #1384) Allow WebFinger discovery for localhost / private hosts by default (fixes #1384) Apr 27, 2026
@silverbucket silverbucket changed the title Allow WebFinger discovery for localhost / private hosts by default (fixes #1384) Allow WebFinger discovery for localhost / private hosts by default Apr 27, 2026

@raucao raucao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The option key is a bit clunky, because it's so long. Wondering if we should turn that into an object instead and then change the timeout one, too (we can still do breaking changes for 2.0).

Comment thread src/remotestorage.ts Outdated
Replace the flat `discoveryAllowPrivateAddresses` and `discoveryTimeout`
config keys with a nested `discovery` group, so callers can write
`{ discovery: { timeout: 1000 } }` (or `{ discovery: { allowPrivateAddresses: false } }`)
without the keys ballooning further as the discovery feature grows.

The `RemoteStorage` constructor now merges the `discovery` sub-object
key by key against the defaults, so a partial override does not
clobber the unspecified subkeys (mirroring how `changeEvents`'
all-or-nothing behaviour was the main wart of the previous shape).

This is a breaking change for direct readers of `config.discoveryTimeout`
/ `config.discoveryAllowPrivateAddresses`, but those keys only ever
shipped in `2.0.0-beta.x`, so the rename is safe.
@silverbucket
silverbucket requested a review from raucao April 28, 2026 21:28

@DougReeder DougReeder left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very good!

Comment thread src/remotestorage.ts Outdated
silverbucket and others added 2 commits April 30, 2026 16:11
Co-authored-by: Doug Reeder <reeder.29@gmail.com>
@silverbucket
silverbucket requested a review from DougReeder April 30, 2026 14:12
Comment thread src/remotestorage.ts

@DougReeder DougReeder left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@raucao raucao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! 👏

The PR description needs to mention the breaking change for the existing discovery timeout config key. At the moment, it only describes the fix.

@silverbucket

Copy link
Copy Markdown
Member Author

@raucao updated!

raucao added 2 commits May 27, 2026 12:52
Fixes class doc layout and makes the hint more prominent where it's
actually needed.
@raucao

raucao commented May 27, 2026

Copy link
Copy Markdown
Member

@param docs can't be used like that for classes it seems:

Screenshot From 2026-05-27 12-33-27

I moved the documentation to a a more appropriate place, which fixes the issue and also makes it more prominent/relevant where it's needed: 7129411

I also added a drive-by commit improving some wording on the same page.

@raucao raucao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@raucao raucao changed the title Allow WebFinger discovery for localhost / private hosts by default Allow WebFinger discovery for localhost/private hosts by default May 27, 2026
@raucao raucao added the feature label May 27, 2026
@raucao
raucao merged commit 5904872 into master May 27, 2026
3 checks passed
@raucao
raucao deleted the bugfix/1384-localhost_discovery branch May 27, 2026 10:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

Discover() rejects localhost / private IPs after webfinger.js v3 upgrade (beta.9 regression)

3 participants