LibreChat/api/server
Danny Avila acd07e8085
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
🗝️ fix: Exempt Admin-Trusted Domains from MCP OAuth Validation (#12255)
* fix: exempt allowedDomains from MCP OAuth SSRF checks (#12254)

The SSRF guard in validateOAuthUrl was context-blind — it blocked
private/internal OAuth endpoints even for admin-trusted MCP servers
listed in mcpSettings.allowedDomains. Add isHostnameAllowed() to
domain.ts and skip SSRF checks in validateOAuthUrl when the OAuth
endpoint hostname matches an allowed domain.

* refactor: thread allowedDomains through MCP connection stack

Pass allowedDomains from MCPServersRegistry through BasicConnectionOptions,
MCPConnectionFactory, and into MCPOAuthHandler method calls so the OAuth
layer can exempt admin-trusted domains from SSRF validation.

* test: add allowedDomains bypass tests and fix registry mocks

Add isHostnameAllowed unit tests (exact, wildcard, case-insensitive,
private IPs). Add MCPOAuthSecurity tests covering the allowedDomains
bypass for initiateOAuthFlow, refreshOAuthTokens, and revokeOAuthToken.
Update registry mocks to include getAllowedDomains.

* fix: enforce protocol/port constraints in OAuth allowedDomains bypass

Replace isHostnameAllowed (hostname-only check) with isOAuthUrlAllowed
which parses the full OAuth URL and matches against allowedDomains
entries including protocol and explicit port constraints — mirroring
isDomainAllowedCore's allowlist logic. Prevents a port-scoped entry
like 'https://auth.internal:8443' from also exempting other ports.

* test: cover auto-discovery and branch-3 refresh paths with allowedDomains

Add three new integration tests using a real OAuth test server:
- auto-discovered OAuth endpoints allowed when server IP is in allowedDomains
- auto-discovered endpoints rejected when allowedDomains doesn't match
- refreshOAuthTokens branch 3 (no clientInfo/config) with allowedDomains bypass

Also rename describe block from ephemeral issue number to durable name.

* docs: explain intentional absence of allowedDomains in completeOAuthFlow

Prevents future contributors from assuming a missing parameter during
security audits — URLs are pre-validated during initiateOAuthFlow.

* test: update initiateOAuthFlow assertion for allowedDomains parameter

* perf: avoid redundant URL parse for admin-trusted OAuth endpoints

Move isOAuthUrlAllowed check before the hostname extraction so
admin-trusted URLs short-circuit with a single URL parse instead
of two. The hostname extraction (new URL) is now deferred to the
SSRF-check path where it's actually needed.
2026-03-15 23:03:12 -04:00
..
controllers 🗝️ fix: Exempt Admin-Trusted Domains from MCP OAuth Validation (#12255) 2026-03-15 23:03:12 -04:00
middleware 🛡️ fix: Enforce MULTI_CONVO and agent ACL checks on addedConvo (#12243) 2026-03-15 17:12:45 -04:00
routes 🛡️ refactor: Scope Action Mutations by Parent Resource Ownership (#12237) 2026-03-15 10:19:29 -04:00
services 🧱 fix: Enforce Agent Access Control on Context and OCR File Loading (#12253) 2026-03-15 23:02:36 -04:00
utils 📏 refactor: Add File Size Limits to Conversation Imports (#12221) 2026-03-14 03:06:29 -04:00
cleanup.js 🪣 fix: Prevent Memory Retention from AsyncLocalStorage Context Propagation (#11942) 2026-02-25 17:41:23 -05:00
experimental.js 🚦 fix: 404 JSON Responses for Unmatched API Routes (#11976) 2026-02-27 22:49:54 -05:00
index.js 🚦 fix: 404 JSON Responses for Unmatched API Routes (#11976) 2026-02-27 22:49:54 -05:00
index.spec.js 🚦 fix: 404 JSON Responses for Unmatched API Routes (#11976) 2026-02-27 22:49:54 -05:00
socialLogins.js 🔒 fix: Secure Cookie Localhost Bypass and OpenID Token Selection in AuthService (#11782) 2026-02-13 10:35:51 -05:00