Summary
The POST /api/admin/default-model/test endpoint accepts user-supplied provider and base_url without authentication. When provider is 'custom' or 'openai-compatible', the base_url flows to SimpleGenericProvider which creates an AsyncOpenAI client pointing to the attacker-specified URL, enabling unauthenticated SSRF to internal cloud metadata, private networks, and localhost.
Details
Root cause: test_default_model in http.py L4542-4631 extracts provider, model_name, api_key, base_url from JSON body with no _require_admin() check. base_url flows through create_model_provider() L498-508 where 'custom'/'openai-compatible' branch passes it to SimpleGenericProvider. In providers.py L791-809, SimpleGenericProvider.init() creates AsyncOpenAI(base_url=attacker_url) which issues HTTP requests to attacker-controlled destinations on chat_completion(). No URL validation or IP restrictions exist.
Core vulnerable code path:
# sdk/src/openagents/sdk/transports/http.py:4542-4592
async def test_default_model(self, request):
"""Test the default LLM model configuration."""
try:
data = await request.json()
provider = data.get("provider")
model_name = data.get("model_name")
api_key = data.get("api_key")
base_url = data.get("base_url")
if not provider:
return web.json_response({"success": False, "error_message": "provider is required"}, status=400)
if not model_name:
return web.json_response({"success": False, "error_message": "model_name is required"}, status=400)
if not api_key:
return web.json_response({"success": False, "error_message": "api_key is required"}, status=400)
from openagents.config.llm_configs import create_model_provider, MODEL_CONFIGS
effective_provider = provider
effective_api_base = base_url
if not effective_api_base and provider in MODEL_CONFIGS:
effective_api_base = MODEL_CONFIGS[provider].get("api_base")
SSRF entry point. User-controlled base_url extracted from JSON body. No _require_admin() authorization check.
# sdk/src/openagents/config/llm_configs.py:498-508
elif provider == "custom" or provider == "openai-compatible":
if not api_base:
raise ValueError("API base URL is required")
return SimpleGenericProvider(
model_name=model_name, api_base=api_base, api_key=api_key, **kwargs
)
'custom' branch passes user-supplied api_base directly to SimpleGenericProvider with no URL validation.
# sdk/src/openagents/lms/providers.py:791-809
class SimpleGenericProvider(BaseModelProvider):
"""Generic provider for OpenAI-compatible APIs."""
def __init__(self, model_name: str, api_base: str, api_key=None, **kwargs):
self.model_name = model_name
self.api_base = api_base
from openai import AsyncOpenAI
if not api_key:
logger.warning(f"No API key provided")
self.client = AsyncOpenAI(base_url=api_base, api_key=api_key or "dummy")
SSRF sink. AsyncOpenAI(base_url=attacker_url) creates HTTP client pointing to attacker-controlled destination.
POC
Prerequisites: OpenAgents HTTP Transport on port 8700, openai package installed, network access. Step 1: POST /api/admin/default-model/test with body {"provider":"custom","model_name":"gpt-4","api_key":"dummy","base_url":"http://169.254.169.254/latest/meta-data/"}. Server issues request to AWS metadata. Step 2: Probe internal services with body {"provider":"custom","model_name":"gpt-4","api_key":"dummy","base_url":"http://localhost:6379/"}. Step 3: Scan internal network by iterating IPs/ports. Expected: server issues HTTP requests to attacker-specified URLs, enabling metadata theft and internal reconnaissance.
Impact
High: Unauthenticated SSRF. Cloud metadata theft, internal network scanning, exploitation of internal APIs. CVSS 7.5.
Remediation
- Add _require_admin() to test_default_model. 2. URL allowlist for known LLM endpoints. 3. Block RFC1918/cloud-metadata IPs. 4. Enforce HTTPS-only. 5. DNS rebinding protections.
Disclosure Notes
Source-code audit of OpenAgents v1. Affected/patch versions to be confirmed.
Supplemental Information
Affected products
- Ecosystem: self-hosted
- Package name: OpenAgents
- Affected versions: v1
- Patched versions: to be confirmed
Severity
- Scoring method: CVSS v3.1
- Score: 7.5
- Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weaknesses
- CWE: CWE-918 Server-Side Request Forgery (SSRF)
Summary
The POST /api/admin/default-model/test endpoint accepts user-supplied provider and base_url without authentication. When provider is 'custom' or 'openai-compatible', the base_url flows to SimpleGenericProvider which creates an AsyncOpenAI client pointing to the attacker-specified URL, enabling unauthenticated SSRF to internal cloud metadata, private networks, and localhost.
Details
Root cause: test_default_model in http.py L4542-4631 extracts provider, model_name, api_key, base_url from JSON body with no _require_admin() check. base_url flows through create_model_provider() L498-508 where 'custom'/'openai-compatible' branch passes it to SimpleGenericProvider. In providers.py L791-809, SimpleGenericProvider.init() creates AsyncOpenAI(base_url=attacker_url) which issues HTTP requests to attacker-controlled destinations on chat_completion(). No URL validation or IP restrictions exist.
Core vulnerable code path:
SSRF entry point. User-controlled base_url extracted from JSON body. No _require_admin() authorization check.
'custom' branch passes user-supplied api_base directly to SimpleGenericProvider with no URL validation.
SSRF sink. AsyncOpenAI(base_url=attacker_url) creates HTTP client pointing to attacker-controlled destination.
POC
Prerequisites: OpenAgents HTTP Transport on port 8700, openai package installed, network access. Step 1: POST /api/admin/default-model/test with body {"provider":"custom","model_name":"gpt-4","api_key":"dummy","base_url":"http://169.254.169.254/latest/meta-data/"}. Server issues request to AWS metadata. Step 2: Probe internal services with body {"provider":"custom","model_name":"gpt-4","api_key":"dummy","base_url":"http://localhost:6379/"}. Step 3: Scan internal network by iterating IPs/ports. Expected: server issues HTTP requests to attacker-specified URLs, enabling metadata theft and internal reconnaissance.
Impact
High: Unauthenticated SSRF. Cloud metadata theft, internal network scanning, exploitation of internal APIs. CVSS 7.5.
Remediation
Disclosure Notes
Source-code audit of OpenAgents v1. Affected/patch versions to be confirmed.
Supplemental Information
Affected products
Severity
Weaknesses