Commit graph

19 commits

Author SHA1 Message Date
Danny Avila
8ba2bde5c1
📦 refactor: Consolidate DB models, encapsulating Mongoose usage in data-schemas (#11830)
* chore: move database model methods to /packages/data-schemas

* chore: add TypeScript ESLint rule to warn on unused variables

* refactor: model imports to streamline access

- Consolidated model imports across various files to improve code organization and reduce redundancy.
- Updated imports for models such as Assistant, Message, Conversation, and others to a unified import path.
- Adjusted middleware and service files to reflect the new import structure, ensuring functionality remains intact.
- Enhanced test files to align with the new import paths, maintaining test coverage and integrity.

* chore: migrate database models to packages/data-schemas and refactor all direct Mongoose Model usage outside of data-schemas

* test: update agent model mocks in unit tests

- Added `getAgent` mock to `client.test.js` to enhance test coverage for agent-related functionality.
- Removed redundant `getAgent` and `getAgents` mocks from `openai.spec.js` and `responses.unit.spec.js` to streamline test setup and reduce duplication.
- Ensured consistency in agent mock implementations across test files.

* fix: update types in data-schemas

* refactor: enhance type definitions in transaction and spending methods

- Updated type definitions in `checkBalance.ts` to use specific request and response types.
- Refined `spendTokens.ts` to utilize a new `SpendTxData` interface for better clarity and type safety.
- Improved transaction handling in `transaction.ts` by introducing `TransactionResult` and `TxData` interfaces, ensuring consistent data structures across methods.
- Adjusted unit tests in `transaction.spec.ts` to accommodate new type definitions and enhance robustness.

* refactor: streamline model imports and enhance code organization

- Consolidated model imports across various controllers and services to a unified import path, improving code clarity and reducing redundancy.
- Updated multiple files to reflect the new import structure, ensuring all functionalities remain intact.
- Enhanced overall code organization by removing duplicate import statements and optimizing the usage of model methods.

* feat: implement loadAddedAgent and refactor agent loading logic

- Introduced `loadAddedAgent` function to handle loading agents from added conversations, supporting multi-convo parallel execution.
- Created a new `load.ts` file to encapsulate agent loading functionalities, including `loadEphemeralAgent` and `loadAgent`.
- Updated the `index.ts` file to export the new `load` module instead of the deprecated `loadAgent`.
- Enhanced type definitions and improved error handling in the agent loading process.
- Adjusted unit tests to reflect changes in the agent loading structure and ensure comprehensive coverage.

* refactor: enhance balance handling with new update interface

- Introduced `IBalanceUpdate` interface to streamline balance update operations across the codebase.
- Updated `upsertBalanceFields` method signatures in `balance.ts`, `transaction.ts`, and related tests to utilize the new interface for improved type safety.
- Adjusted type imports in `balance.spec.ts` to include `IBalanceUpdate`, ensuring consistency in balance management functionalities.
- Enhanced overall code clarity and maintainability by refining type definitions related to balance operations.

* feat: add unit tests for loadAgent functionality and enhance agent loading logic

- Introduced comprehensive unit tests for the `loadAgent` function, covering various scenarios including null and empty agent IDs, loading of ephemeral agents, and permission checks.
- Enhanced the `initializeClient` function by moving `getConvoFiles` to the correct position in the database method exports, ensuring proper functionality.
- Improved test coverage for agent loading, including handling of non-existent agents and user permissions.

* chore: reorder memory method exports for consistency

- Moved `deleteAllUserMemories` to the correct position in the exported memory methods, ensuring a consistent and logical order of method exports in `memory.ts`.
2026-03-21 14:28:53 -04:00
Danny Avila
11ab5f6ee5
🛂 fix: Reject OpenID Email Fallback When Stored openidId Mismatches Token Sub (#12312)
* 🔐 fix: Reject OpenID email fallback when stored openidId mismatches token sub

When `findOpenIDUser` falls back to email lookup after the primary
`openidId`/`idOnTheSource` query fails, it now rejects any user whose
stored `openidId` differs from the incoming JWT subject claim. This
closes an account-takeover vector where a valid IdP JWT containing a
victim's email but a different `sub` could authenticate as the victim
when OPENID_REUSE_TOKENS is enabled.

The migration path (user has no `openidId` yet) is unaffected.

* test: Validate openidId mismatch guard in email fallback path

Update `findOpenIDUser` unit tests to assert that email-based lookups
returning a user with a different `openidId` are rejected with
AUTH_FAILED. Add matching integration test in `openIdJwtStrategy.spec`
exercising the full verify callback with the real `findOpenIDUser`.

* 🔐 fix: Remove redundant `openidId` truthiness check from mismatch guard

The `&& openidId` middle term in the guard condition caused it to be
bypassed when the incoming token `sub` was empty or undefined. Since
the JS callers can pass `payload?.sub` (which may be undefined), this
created a path where the guard never fired and the email fallback
returned the victim's account. Removing the term ensures the guard
rejects whenever the stored openidId differs from the incoming value,
regardless of whether the incoming value is falsy.

* test: Cover falsy openidId bypass and openidStrategy mismatch rejection

Add regression test for the guard bypass when `openidId` is an empty
string and the email lookup finds a user with a stored openidId.

Add integration test in openidStrategy.spec.js exercising the
mismatch rejection through the full processOpenIDAuth callback,
ensuring both OIDC paths (JWT reuse and standard callback) are
covered.

Restore intent-documenting comment on the no-provider fixture.
2026-03-19 16:42:57 -04:00
Danny Avila
8271055c2d
📦 chore: Bump @librechat/agents to v3.1.56 (#12258)
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
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
* 📦 chore: Bump `@librechat/agents` to v3.1.56

* chore: resolve type error, URL property check in isMCPDomainAllowed function
2026-03-15 23:51:41 -04:00
Danny Avila
acd07e8085
🗝️ fix: Exempt Admin-Trusted Domains from MCP OAuth Validation (#12255)
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 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
Danny Avila
f7ab5e645a
🫷 fix: Validate User-Provided Base URL in Endpoint Init (#12248)
* 🛡️ fix: Block SSRF via user-provided baseURL in endpoint initialization

User-provided baseURL values (when endpoint is configured with
`user_provided`) were passed through to the OpenAI SDK without
validation. Combined with `directEndpoint`, this allowed arbitrary
server-side requests to internal/metadata URLs.

Adds `validateEndpointURL` that checks against known SSRF targets
and DNS-resolves hostnames to block private IPs. Applied in both
custom and OpenAI endpoint initialization paths.

* 🧪 test: Add validateEndpointURL SSRF tests

Covers unparseable URLs, localhost, private IPs, link-local/metadata,
internal Docker/K8s hostnames, DNS resolution to private IPs, and
legitimate public URLs.

* 🛡️ fix: Add protocol enforcement and import order fix

- Reject non-HTTP/HTTPS schemes (ftp://, file://, data:, etc.) in
  validateEndpointURL before SSRF hostname checks
- Document DNS rebinding limitation and fail-open semantics in JSDoc
- Fix import order in custom/initialize.ts per project conventions

* 🧪 test: Expand SSRF validation coverage and add initializer integration tests

Unit tests for validateEndpointURL:
- Non-HTTP/HTTPS schemes (ftp, file, data)
- IPv6 loopback, link-local, and unique-local addresses
- .local and .internal TLD hostnames
- DNS fail-open path (lookup failure allows request)

Integration tests for initializeCustom and initializeOpenAI:
- Guard fires when userProvidesURL is true
- Guard skipped when URL is system-defined or falsy
- SSRF rejection propagates and prevents getOpenAIConfig call

* 🐛 fix: Correct broken env restore in OpenAI initialize spec

process.env was captured by reference, not by value, making the
restore closure a no-op. Snapshot individual env keys before mutation
so they can be properly restored after each test.

* 🛡️ fix: Throw structured ErrorTypes for SSRF base URL validation

Replace plain-string Error throws in validateEndpointURL with
JSON-structured errors using type 'invalid_base_url' (matching new
ErrorTypes.INVALID_BASE_URL enum value). This ensures the client-side
Error component can look up a localized message instead of falling
through to the raw-text default.

Changes across workspaces:
- data-provider: add INVALID_BASE_URL to ErrorTypes enum
- packages/api: throwInvalidBaseURL helper emits structured JSON
- client: add errorMessages entry and localization key
- tests: add structured JSON format assertion

* 🧹 refactor: Use ErrorTypes enum key in Error.tsx for consistency

Replace bare string literal 'invalid_base_url' with computed property
[ErrorTypes.INVALID_BASE_URL] to match every other entry in the
errorMessages map.
2026-03-15 18:41:59 -04:00
Danny Avila
07d0ce4ce9
🪤 fix: Fail-Closed MCP Domain Validation for Unparseable URLs (#12245)
* 🛡️ fix: Fail-closed MCP domain validation for unparseable URLs

`isMCPDomainAllowed` returned true (allow) when `extractMCPServerDomain`
could not parse the URL, treating it identically to a stdio transport.
A URL containing template placeholders or invalid syntax bypassed the
domain allowlist, then `processMCPEnv` resolved it to a valid—and
potentially disallowed—host at connection time.

Distinguish "no URL" (stdio, allowed) from "has URL but unparseable"
(rejected when an allowlist is active) by checking whether `config.url`
is an explicit non-empty string before falling through to the stdio path.

When no allowlist is configured the guard does not fire—unparseable URLs
fall through to connection-level SSRF protection via
`createSSRFSafeUndiciConnect`, preserving legitimate `customUserVars`
template-URL configs.

* test: Expand MCP domain validation coverage for invalid/templated URLs

Cover all branches of the fail-closed guard:
- Invalid/templated URLs rejected when allowlist is configured
- Invalid/templated URLs allowed when no allowlist (null/undefined/[])
- Whitespace-only and empty-string URLs treated as absent across all
  allowedDomains configurations
- Stdio configs (no url property) remain allowed
2026-03-15 17:08:43 -04:00
Danny Avila
a0b4949a05
🛡️ fix: Cover full fe80::/10 link-local range in IPv6 check (#12244)
* 🛡️ fix: Cover full fe80::/10 link-local range in SSRF IPv6 check

The `isPrivateIP` check used `startsWith('fe80')` which only matched
fe80:: but missed fe90::–febf:: (the rest of the RFC 4291 fe80::/10
link-local block). Replace with a proper bitwise hextet check.

* 🛡️ fix: Guard isIPv6LinkLocal against parseInt partial-parse on hostnames

parseInt('fe90.example.com', 16) stops at the dot and returns 0xfe90,
which passes the bitmask check and false-positives legitimate domains.

Add colon-presence guard (IPv6 literals always contain ':') and a hex
regex validation on the first hextet before parseInt.

Also document why fc/fd use startsWith while fe80::/10 needs bitwise.

*  test: Harden IPv6 link-local SSRF tests with false-positive guards

- Assert fe90/fea0/febf hostnames are NOT blocked (regression guard)
- Add feb0::1 and bracket form [fe90::1] to isPrivateIP coverage
- Extend resolveHostnameSSRF tests for fe90::1 and febf::1
2026-03-15 17:07:55 -04:00
Danny Avila
4a8a5b5994
🔒 fix: Hex-normalized IPv4-mapped IPv6 in Domain Validation (#12130)
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
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
* 🔒 fix: handle hex-normalized IPv4-mapped IPv6 in domain validation

* fix: Enhance IPv6 private address detection in domain validation

- Added tests for detecting IPv4-compatible, 6to4, NAT64, and Teredo addresses.
- Implemented `extractEmbeddedIPv4` function to identify private IPv4 addresses within various IPv6 formats.
- Updated `isPrivateIP` function to utilize the new extraction logic for improved accuracy in address validation.

* fix: Update private IPv4 detection logic in domain validation

- Enhanced the `isPrivateIPv4` function to accurately identify additional private and non-routable IPv4 ranges.
- Adjusted the return logic in `resolveHostnameSSRF` to utilize the updated private IP detection for improved hostname validation.

* test: Expand private IP detection tests in domain validation

- Added tests for additional private IPv4 ranges including 0.0.0.0/8, 100.64.0.0/10, 192.0.0.0/24, and 198.18.0.0/15.
- Updated existing tests to ensure accurate detection of private and multicast IP addresses in the `isPrivateIP` function.
- Enhanced `resolveHostnameSSRF` to correctly identify private literal IPv4 addresses without DNS lookup.

* refactor: Rename and enhance embedded IPv4 detection in IPv6 addresses

- Renamed `extractEmbeddedIPv4` to `hasPrivateEmbeddedIPv4` for clarity on its purpose.
- Updated logic to accurately check for private IPv4 addresses embedded in Teredo, 6to4, and NAT64 IPv6 formats.
- Improved the `isPrivateIP` function to utilize the new naming and logic for better readability and accuracy.
- Enhanced documentation for clarity on the functionality of the updated methods.

* feat: Enhance private IPv4 detection in embedded IPv6 addresses

- Added additional checks in `hasPrivateEmbeddedIPv4` to ensure only valid private IPv4 formats are recognized.
- Improved the logic for identifying private IPv4 addresses embedded within various IPv6 formats, enhancing overall accuracy.

* test: Add additional test for hostname resolution in SSRF detection

- Included a new test case in `resolveHostnameSSRF` to validate the detection of private IPv4 addresses embedded in IPv6 formats for the hostname 'meta.example.com'.
- Enhanced existing tests to ensure comprehensive coverage of hostname resolution scenarios.

* fix: Set redirect option to 'manual' in undiciFetch calls

- Updated undiciFetch calls in MCPConnection to include the redirect option set to 'manual' for better control over HTTP redirects.
- Added documentation comments regarding SSRF pre-checks for WebSocket connections, highlighting the limitations of the current SDK regarding DNS resolution.

* test: Add integration tests for MCP SSRF protections

- Introduced a new test suite for MCP SSRF protections, verifying that MCPConnection does not follow HTTP redirects to private IPs and blocks WebSocket connections to private IPs when SSRF protection is enabled.
- Implemented tests to ensure correct behavior of the connection under various scenarios, including redirect handling and WebSocket DNS resolution.

* refactor: Improve SSRF protection logic for WebSocket connections

- Enhanced the SSRF pre-check for WebSocket connections to validate resolved IPs, ensuring that allowlisting a domain does not grant trust to its resolved IPs at runtime.
- Updated documentation comments to clarify the limitations of the current SDK regarding DNS resolution and the implications for SSRF protection.

* test: Enhance MCP SSRF protection tests for redirect handling and WebSocket connections

- Updated tests to ensure that MCPConnection does not follow HTTP redirects to private IPs, regardless of SSRF protection settings.
- Added checks to verify that WebSocket connections to hosts resolving to private IPs are blocked, even when SSRF protection is disabled.
- Improved documentation comments for clarity on the behavior of the tests and the implications for SSRF protection.

* test: Refactor MCP SSRF protection test for WebSocket connection errors

- Updated the test to use `await expect(...).rejects.not.toThrow(...)` for better readability and clarity.
- Simplified the error handling logic while ensuring that SSRF rejections are correctly validated during connection failures.
2026-03-07 20:13:52 -05:00
Danny Avila
924be3b647
🛡️ fix: Implement TOCTOU-Safe SSRF Protection for Actions and MCP (#11722)
* refactor: better SSRF Protection in Action and Tool Services

- Added `createSSRFSafeAgents` function to create HTTP/HTTPS agents that block connections to private/reserved IP addresses, enhancing security against SSRF attacks.
- Updated `createActionTool` to accept a `useSSRFProtection` parameter, allowing the use of SSRF-safe agents during tool execution.
- Modified `processRequiredActions` and `loadAgentTools` to utilize the new SSRF protection feature based on allowed domains configuration.
- Introduced `resolveHostnameSSRF` function to validate resolved IPs against private ranges, preventing potential SSRF vulnerabilities.
- Enhanced tests for domain resolution and private IP detection to ensure robust SSRF protection mechanisms are in place.

* feat: Implement SSRF protection in MCP connections

- Added `createSSRFSafeUndiciConnect` function to provide SSRF-safe DNS lookup options for undici agents.
- Updated `MCPConnection`, `MCPConnectionFactory`, and `ConnectionsRepository` to include `useSSRFProtection` parameter, enabling SSRF protection based on server configuration.
- Enhanced `MCPManager` and `UserConnectionManager` to utilize SSRF protection when establishing connections.
- Updated tests to validate the integration of SSRF protection across various components, ensuring robust security measures are in place.

* refactor: WS MCPConnection with SSRF protection and async transport construction

- Added `resolveHostnameSSRF` to validate WebSocket hostnames against private IP addresses, enhancing SSRF protection.
- Updated `constructTransport` method to be asynchronous, ensuring proper handling of SSRF checks before establishing connections.
- Improved error handling for WebSocket transport to prevent connections to potentially unsafe addresses.

* test: Enhance ActionRequest tests for SSRF-safe agent passthrough

- Added tests to verify that httpAgent and httpsAgent are correctly passed to axios.create when provided in ActionRequest.
- Included scenarios to ensure agents are not included when no options are specified.
- Enhanced coverage for POST requests to confirm agent passthrough functionality.
- Improved overall test robustness for SSRF protection in ActionRequest execution.
2026-02-11 22:09:58 -05:00
Danny Avila
b6af884dd2
🔐 feat: Admin Auth. Routes with Secure Cross-Origin Token Exchange (#11297)
* feat: implement admin authentication with OpenID & Local Auth proxy support

* feat: implement admin OAuth exchange flow with caching support

- Added caching for admin OAuth exchange codes with a short TTL.
- Introduced new endpoints for generating and exchanging admin OAuth codes.
- Updated relevant controllers and routes to handle admin panel redirects and token exchanges.
- Enhanced logging for better traceability of OAuth operations.

* refactor: enhance OpenID strategy mock to support multiple verify callbacks

- Updated the OpenID strategy mock to store and retrieve verify callbacks by strategy name.
- Improved backward compatibility by maintaining a method to get the last registered callback.
- Adjusted tests to utilize the new callback retrieval methods, ensuring clarity in the verification process for the 'openid' strategy.

* refactor: reorder import statements for better organization

* refactor: admin OAuth flow with improved URL handling and validation

- Added a utility function to retrieve the admin panel URL, defaulting to a local development URL if not set in the environment.
- Updated the OAuth exchange endpoint to include validation for the authorization code format.
- Refactored the admin panel redirect logic to handle URL parsing more robustly, ensuring accurate origin comparisons.
- Removed redundant local URL definitions from the codebase for better maintainability.

* refactor: remove deprecated requireAdmin middleware and migrate to TypeScript

- Deleted the old requireAdmin middleware file and its references in the middleware index.
- Introduced a new TypeScript version of the requireAdmin middleware with enhanced error handling and logging.
- Updated routes to utilize the new requireAdmin middleware, ensuring consistent access control for admin routes.

* feat: add requireAdmin middleware for admin role verification

- Introduced requireAdmin middleware to enforce admin role checks for authenticated users.
- Implemented comprehensive error handling and logging for unauthorized access attempts.
- Added unit tests to validate middleware functionality and ensure proper behavior for different user roles.
- Updated middleware index to include the new requireAdmin export.
2026-01-28 17:44:31 -05:00
Danny Avila
3b41e392ba
🔒 fix: SSRF Protection and Domain Handling in MCP Server Config (#11234)
* 🔒 fix: Enhance SSRF Protection and Domain Handling in MCP Server Configuration

- Updated the `extractMCPServerDomain` function to return the full origin (protocol://hostname:port) for improved protocol/port matching against allowed domains.
- Enhanced tests for `isMCPDomainAllowed` to validate domain access for internal hostnames and .local TLDs, ensuring proper SSRF protection.
- Added detailed comments in the configuration file to clarify security measures regarding allowed domains and internal target access.

* refactor: Domain Validation for WebSocket Protocols in Action and MCP Handling

- Added comprehensive tests to validate handling of WebSocket URLs in `isActionDomainAllowed` and `isMCPDomainAllowed` functions, ensuring that WebSocket protocols are rejected for OpenAPI Actions while allowed for MCP.
- Updated domain validation logic to support HTTP, HTTPS, WS, and WSS protocols, enhancing security and compliance with specifications.
- Refactored `parseDomainSpec` to improve protocol recognition and validation, ensuring robust handling of domain specifications.
- Introduced detailed comments to clarify the purpose and security implications of domain validation functions.
2026-01-06 13:04:52 -05:00
Danny Avila
4fd09946d2
🔒 fix: Better SSRF protection for Actions (#11143)
Addresses Server-Side Request Forgery vulnerability that allowed authenticated
attackers to interact with arbitrary internal/external HTTP services via the
Actions feature, including the internal RAG API, localhost services, and cloud
metadata endpoints.

## Security Changes

### 1. SSRF Target Blocklist (when allowedDomains is empty)
- Block localhost and loopback addresses (127.0.0.0/8, ::1)
- Block private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Block link-local/cloud metadata IPs (169.254.0.0/16)
- Block common internal Docker/Kubernetes service names (rag_api, redis, mongo, etc.)
- Block .internal and .local TLDs

Admins can still explicitly allow internal targets by adding them to
`actions.allowedDomains` in librechat.yaml.

### 2. Protocol and Port Restrictions
Enhanced `allowedDomains` to support protocol and port constraints:
- `example.com` - any protocol, any port (existing behavior)
- `https://example.com` - HTTPS only, any port
- `https://api.example.com:8443` - HTTPS only, port 8443 only

This allows admins to restrict actions to specific protocols/ports, preventing
attackers from accessing unintended services on allowed domains.

### 3. Redirect-based SSRF Prevention
Disabled automatic redirect following in action HTTP requests (`maxRedirects: 0`).
This prevents attackers from bypassing domain restrictions by:
1. Pointing action to allowed external domain
2. External domain redirects to internal service (e.g., 127.0.0.1)
3. Server follows redirect and accesses internal service

## Files Changed
- packages/api/src/auth/domain.ts: Added isSSRFTarget(), parseDomainSpec(),
  updated isActionDomainAllowed() with protocol/port matching
- packages/api/src/auth/domain.spec.ts: Added tests for SSRF protection,
  protocol restrictions, and port restrictions
- packages/data-provider/src/actions.ts: Added maxRedirects: 0 to axios config

## Configuration Example
# librechat.yaml
actions:
  allowedDomains:
    - "https://api.example.com"        # HTTPS only
    - "https://api.example.com:8443"   # HTTPS + specific port
    - "http://localhost:3000"          # Admin override for local devRef: SBA-ADV-20251205-02
CVSSv3: 9.1 (Critical) - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:L
2025-12-29 15:09:55 -05:00
Atef Bellaaj
95a69df70e
🔒 feat: Add MCP server domain restrictions for remote transports (#11013)
* 🔒 feat: Add MCP server domain restrictions for remote transports

* 🔒 feat: Implement comprehensive MCP error handling and domain validation

- Added `handleMCPError` function to centralize error responses for domain restrictions and inspection failures.
- Introduced custom error classes: `MCPDomainNotAllowedError` and `MCPInspectionFailedError` for better error management.
- Updated MCP server controllers to utilize the new error handling mechanism.
- Enhanced domain validation logic in `createMCPTools` and `createMCPTool` functions to prevent operations on disallowed domains.
- Added tests for runtime domain validation scenarios to ensure correct behavior.

* chore: import order

* 🔒 feat: Enhance domain validation in MCP tools with user role-based restrictions

- Integrated `getAppConfig` to fetch allowed domains based on user roles in `createMCPTools` and `createMCPTool` functions.
- Removed the deprecated `getAllowedDomains` method from `MCPServersRegistry`.
- Updated tests to verify domain restrictions are applied correctly based on user roles.
- Ensured that domain validation logic is consistent and efficient across tool creation processes.

* 🔒 test: Refactor MCP tests to utilize configurable app settings

- Introduced a mock for `getAppConfig` to enhance test flexibility.
- Removed redundant mock definition to streamline test setup.
- Ensured tests are aligned with the latest domain validation logic.

---------

Co-authored-by: Atef Bellaaj <slalom.bellaaj@external.daimlertruck.com>
Co-authored-by: Danny Avila <danny@librechat.ai>
2025-12-18 13:57:49 -05:00
Danny Avila
d5d362e52b
📬 refactor: Normalize Email Handling in User Methods (#10743)
- Updated the `findUser` method to normalize email fields to lowercase and trimmed whitespace for case-insensitive matching.
- Enhanced the `normalizeEmailInCriteria` function to handle email normalization in search criteria, including `` conditions.
- Added tests to ensure email normalization works correctly across various scenarios, including case differences and whitespace handling.
2025-12-01 09:41:25 -05:00
Danny Avila
861ef98d29
📫 refactor: OpenID Email Claim Fallback (#10296)
* 📫 refactor: Enhance OpenID email Fallback

* Updated email retrieval logic to use preferred_username or upn if email is not available.
* Adjusted logging and user data assignment to reflect the new email handling approach.
* Ensured email domain validation checks the correct email source.

* 🔄 refactor: Update Email Domain Validation Logic

* Modified `isEmailDomainAllowed` function to return true for falsy emails and missing domain restrictions.
* Added new test cases to cover scenarios with and without domain restrictions.
* Ensured proper validation when domain restrictions are present.
2025-10-29 12:57:43 -04:00
Danny Avila
a1471c2f37
📧 fix: Case-Insensitive Domain Matching (#9868)
Some checks failed
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Has been cancelled
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Has been cancelled
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Has been cancelled
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Has been cancelled
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Has been cancelled
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Has been cancelled
* chore: move domain related functions to `packages/api`

* fix: isEmailDomainAllowed for case-insensitive domain matching

- Added tests to validate case-insensitive matching for email domains in various scenarios.
- Updated isEmailDomainAllowed function to convert email domains to lowercase for consistent comparison.
- Improved handling of null/undefined entries in allowedDomains.

* ci: Mock isEmailDomainAllowed in samlStrategy tests

- Added a mock implementation for isEmailDomainAllowed to return true in samlStrategy tests, ensuring consistent behavior during test execution.

* ci: Update import of isEmailDomainAllowed in ldapStrategy tests

- Changed the import of isEmailDomainAllowed from the domains service to the api package for consistency and to reflect recent refactoring.
2025-09-27 21:20:19 -04:00
Danny Avila
bcec5bfceb
🆔 fix: Prioritize Immutable Sub Claim for OIDC User ID (#9788)
* add use of immutable claims to identify user object

* fix semicolons

* update email attribute on change

* replace ternary expressions

* fix semicolon

* chore: add typing

* chore: reorder fields in `findOpenIDUser`

* refactor: optimize user lookup logic in `findOpenIDUser` function to minimize database roundtrips

* refactor: integrate findOpenIDUser for improved user retrieval in refreshController

* refactor: improve error logging for invalid refresh tokens in refreshController

* ci: mock findUser correctly in openidStrategy tests

* test: add unit tests for findOpenIDUser function to enhance user retrieval logic

---------

Co-authored-by: Joachim Keltsch <joachim.keltsch@daimlertruck.com>
2025-09-23 14:46:53 -04:00
Danny Avila
cd73cb0b3e
🔐 fix: Image Validation when Reusing OpenID Token (#9458)
* 🔧 fix: Enhance OpenID token handling with user ID for image path validation

* 🔧 fix: Change logger level to error for user info fetch failure and remove redundant info log in OpenID user lookup

* 🔧 refactor: Remove validateImageRequest from middleware exports and enhance validation logic in validateImageRequest.js

* Removed validateImageRequest from the middleware index.
* Improved error handling and validation checks in validateImageRequest.js, including handling of OpenID tokens, URL length, and malformed URLs.
* Updated tests in validateImages.spec.js to cover new validation scenarios and edge cases.
2025-09-05 03:12:17 -04:00
Danny Avila
78d735f35c
📧 fix: Missing Email fallback in openIdJwtLogin (#9311)
* 📧 fix: Missing Email fallback in `openIdJwtLogin`

* chore: Add auth module export to index
2025-08-27 12:59:40 -04:00