RocketChat / RocketChat/Rocket.Chat

Custom OAuth token exchange ignores SSRF_Allowlist setting

Open Beginner friendly
#40,586 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: bug
Dominant language
TypeScript
Stars
46.1k
Forks
13.9k
Avg merge
3d 3h
Merged PRs (30d)
130

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in app/custom-oauth/server/custom_oauth_server.js and inspect the getAccessToken and getIdentity fetch calls, then compare their options with the allowList usage in app/apps/server/bridges/http.ts. Done means both Custom OAuth requests honor settings.get('SSRF_Allowlist'), allowing configured private hosts while preserving SSRF validation for other hosts.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
backend, security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.