Skip to content

Custom OAuth token exchange ignores SSRF_Allowlist setting #40586

@ugoenyioha

Description

@ugoenyioha

Description

The Custom OAuth provider's getAccessToken function in app/custom-oauth/server/custom_oauth_server.js calls fetch() (from @rocket.chat/server-fetch) without passing the allowList option. This means the SSRF_Allowlist admin setting is completely ignored during OAuth token exchanges.

This makes it impossible to use Custom OAuth with an identity provider on a private IP (e.g., 192.168.x.x, 10.x.x.x) in self-hosted/homelab deployments, even when the administrator has explicitly allowlisted the host in Administration > Settings > General > SSRF Protection > SSRF Allowlist.

Steps to Reproduce

  1. Deploy Rocket.Chat 8.2.0 self-hosted
  2. Configure a Custom OAuth provider pointing at an IdP on a private IP (e.g., WSO2, Keycloak, Authentik at https://idp.local:9443)
  3. Add idp.local and its IP to the SSRF Allowlist in Admin > General > SSRF Protection
  4. Click "Login with [Provider]"

Expected Behavior

The SSRF allowlist should permit the token exchange request to the allowlisted host.

Actual Behavior

The token exchange fails with:

SSRF validation failed for URL https://idp.local/oauth2/token
Error: Failed to complete OAuth handshake with [provider] at https://idp.local/oauth2/token. error-ssrf-validation-failed

Root Cause

In app/custom-oauth/server/custom_oauth_server.js, the getAccessToken method calls:

const request = await fetch(`${this.tokenPath}`, {
    method: 'POST',
    headers,
    body: params
});

This does not pass allowList: settings.get('SSRF_Allowlist') in the fetch options.

Compare with other internal fetch calls (e.g., in app/apps/server/bridges/http.ts line ~131765) which correctly pass:

{
    allowList: settings.get('SSRF_Allowlist')
}

The same issue applies to the getIdentity method which also calls fetch() without allowList.

Suggested Fix

Pass the SSRF allowlist to all fetch calls in the Custom OAuth module:

const request = await fetch(`${this.tokenPath}`, {
    method: 'POST',
    headers,
    body: params,
    allowList: settings.get('SSRF_Allowlist')
});

Impact

This affects all self-hosted Rocket.Chat deployments where the OAuth/OIDC provider is on the same private network. This is the standard deployment pattern for homelabs, on-premise enterprise, and air-gapped environments.

Version

  • Rocket.Chat: 8.2.0
  • Node.js: 22.16.0

Workaround

Patch @rocket.chat/server-fetch/dist/helpers.js via an init container to whitelist the specific private IP in the isIpInAnyRange function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    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