Gửi #979789: Conductor >= 3.31.2 (audited commit ce46eac) server-side request forgery (CWE-918)thông tin

tiêu đềConductor >= 3.31.2 (audited commit ce46eac) server-side request forgery (CWE-918)
Mô tảAgentSpan API-spec discovery fetches an unrestricted attacker-selected URL AgentSpan API-spec discovery fetches an unrestricted attacker-selected URL Data flow: HTTP JSON AgentStartRequest.agentConfig.tools[].config.url or spec_url at POST /api/agent/start → ListApiToolsTask HttpClient.send(HttpRequest) while fetching specUrl AFFECTED INTERFACES - POST /api/agent/start with inline agentConfig API tool config.url/spec_url and non-empty prompt Primary route detail: The direct interface is POST /api/agent/start with a JSON AgentStartRequest containing a non-empty prompt and inline agentConfig. The nested agentConfig.tools[] list may contain an API tool whose config.url or config.spec_url is an arbitrary API-spec URL. The same source can be compiled through POST /api/agent/compile or registered through POST /api/agent/deploy, but those routes do not themselves execute the fetch; /start is the execution trigger. The controller is enabled only when conductor.integrations.ai.enabled=true. The request must pass the normal Conductor deployment authentication/authorization boundary and the agent must be configured sufficiently for execution; no anonymous-access claim is made. Harmless local-shape example, not sent by this audit: {"prompt":"local test","agentConfig":{"name":"local_api","model":"configured-model","tools":[{"name":"catalog","toolType":"api","config":{"url":"http://127.0.0.1:18083/openapi.json"}}]}} ROOT CAUSE The explicit taint flow is: HTTP JSON AgentStartRequest.agentConfig.tools[].config.url → AgentController.startAgent() (AgentController.java:91-94) → AgentService.start() (AgentService.java:217-227) → startInline() (:261-293) → AgentCompiler.compile() → ToolCompiler.buildApiDiscoveryTasks() (ToolCompiler.java:948-993) → generated LIST_API_TOOLS task input specUrl → ListApiToolsTask.start() (ListApiToolsTask.java:97-113) → fetchSpec()/attemptFetch() (:180-206) → sendWithValidatedRedirects() (:242-253) → URI.create(currentUrl) / HttpRequest → httpClient.send(...). AgentStartRequest.java:49-72 accepts the inline configuration and ToolConfig.java:30-50 carries the type-specific config map. The compiler reads url or spec_url without a host or network-range check and emits it unchanged as specUrl. The task then creates and sends a Java HttpClient GET request to that value. The code disables automatic redirects, limits redirect count, rejects CR/LF in headers, and avoids forwarding sensitive headers across origins, but it never rejects loopback, link-local, RFC1918, reserved, metadata, or other unintended destinations. The sensitive sink is the outbound server-side HTTP request and response read (httpClient.send with BodyHandlers.ofByteArray), not merely the URL field. The root cause is treating redirect and credential handling as a destination policy. The fetched body is parsed as an OpenAPI/Swagger/Postman document and placed into task output, so an attacker can make the Conductor server access a reachable HTTP service and consume its response. This is distinct from the generic workflow HTTP task (RestTemplate sink) and from the MCP server configuration (OkHttp sink), which we reported separately: the source field, compiler, system task, sink implementation, and execution path are different. Impact is server-side access to HTTP services reachable from the Conductor server's network identity, with response bytes returned into workflow execution data. Triggering requires AI integration, an agent-start principal, and an API tool configuration; this audit contacted no internal, cloud, third-party, or real user service. PROOF OF CONCEPT Baseline: commit ce46eac, server on 127.0.0.1:18080 with conductor.integrations.ai.enabled=true. The destination is a test-local HTTP listener at 192.168.240.2:18081 (a separate container on a test-only bridge network), so nothing leaves the test host; any host/port reachable from the server can be substituted. 1. Start an agent whose inline API tool points at the listener (no Authorization header): $ cat agent-start.json { "prompt": "local-api-spec-canary", "agentConfig": { "name": "api-discovery-test", "description": "local API discovery validation", "model": "<provider>/<model configured on the instance>", "instructions": "Use the available local catalog and finish promptly.", "maxTurns": 1, "timeoutSeconds": 5, "tools": [ { "name": "local_catalog", "description": "local API catalog", "toolType": "api", "config": { "url": "http://192.168.240.2:18081/openapi.json" } } ] } } $ curl -s -X POST 'http://127.0.0.1:18080/api/agent/start' \ -H 'Content-Type: application/json' -d @agent-start.json {"executionId":"2286de8f-0bbe-4187-b721-65e495021067","agentName":"api-discovery-test","requiredWorkers":[]} 2. What the listener received - the server-side fetch issued by the generated LIST_API_TOOLS task: $ cat mock-requests.jsonl method=GET path=/openapi.json canary=local-ssrf-canary body="" 3. Task output (GET /api/agent/executions/{executionId}): the discovery step on the Conductor server fetched the caller-supplied URL and handed the parsed document back into the execution data: {"taskType": "LIST_API_TOOLS", "status": "COMPLETED", "inputData": {"specUrl": "http://192.168.240.2:18081/openapi.json"}, "outputData": {"tools": [], "baseUrl": "http://192.168.240.2:18081", "format": "openapi3"}} The address the caller supplied is what the server fetched, and the base URL of the parsed document (192.168.240.2:18081) is returned in the task output: the caller both selects the destination and reads the response body. IMPACT See the interface and root-cause sections: an actor who satisfies the stated preconditions makes the server perform a request or operation on a destination/target of the attacker's choosing, crossing the trust boundary described above. - Project repository: https://github.com/conductor-oss/conductor - Security policy: `SECURITY.md` in that repository. - **Vendor contact**: GitHub Private Vulnerability Reporting - conductor-oss/conductor - **Status**: vendor notified 2026-09-14 through GitHub Private Vulnerability Reporting; private report https://github.com/conductor-oss/conductor/security/advisories/GHSA-g2c5-2x77-q7xv; not publicly disclosed; no CVE assigned - **Duplicate check**: public advisories (NVD/OSV/GitHub) and the project issue tracker were searched before reporting; please tell us if this duplicates something already tracked internally.
Người dùng
 lucasg2g (UID 84737)
Đệ trình15/09/2026 09:21 (cách đây 29 ngày)
Kiểm duyệt12/10/2026 15:14 (27 days later)
Trạng tháiđược chấp nhận
Mục VulDB416898 [conductor-oss conductor 3.31.2 API Tool Configuration ListApiToolsTask.java ListApiToolsTask.start specUrl nâng cao đặc quyền]
điểm17

Do you want to use VulDB in your project?

Use the official API to access entries easily!