Summary
The HTTP_TASK system task passes user-controlled URIs directly to restTemplate.exchange() with no restrictions on what hosts can be reached. This enables Server-Side Request Forgery (SSRF): anyone who can define or modify a workflow can instruct the Conductor server to make HTTP requests to internal infrastructure.
CodeQL Alert #2 · http-task/.../HttpTask.java:175 · severity: error
The Problem
// HttpTask.java:174-178
ResponseEntity<String> responseEntity =
restTemplate.exchange(
input.getUri(), // ← fully user-controlled, no validation
HttpMethod.valueOf(input.getMethod()),
request,
String.class);
There is no validation of input.getUri() before the call. An attacker with access to workflow definition APIs can target:
- Cloud metadata endpoints —
http://169.254.169.254/latest/meta-data/ (AWS IMDSv1, GCP, Azure) to steal instance credentials
- RFC 1918 internal services —
http://10.x.x.x/, http://192.168.x.x/, http://172.16-31.x.x/
- Loopback —
http://localhost:8080/api/admin/... (Conductor's own admin API)
- Internal DNS names —
http://internal-db-host:5432/
Why This Is By-Design — and Still a Problem
The HTTP task is intentionally designed to call external endpoints — that's its entire purpose. The issue is the absence of any configurable guard rails. Most production deployments need to reach external services, but should not allow the Conductor server itself to become a proxy into its own internal network.
Proposed Solution
Add a configurable HttpTaskProperties class (or extend existing config) with:
- Block-by-default list: RFC 1918 ranges, loopback (
127.0.0.0/8), link-local (169.254.0.0/16), and ::1
- Allowlist (
conductor.system-task.http.allowed-hosts): explicit patterns that override the block list for legitimate internal calls
- Denylist (
conductor.system-task.http.denied-hosts): additional patterns to block beyond defaults
- URI validation at the start of
httpCall(), before restTemplate.exchange() is called
Example config:
conductor:
system-task:
http:
deny-internal-network: true # default: true
allowed-hosts:
- "api.trusted-partner.com"
denied-hosts:
- "*.internal.corp"
Threat Model Note
Risk is higher in multi-tenant or externally-accessible Conductor deployments where untrusted parties can submit workflow definitions. In fully internal, trusted-user-only deployments the practical risk is lower, but the fix is still correct defense-in-depth.
References
Summary
The
HTTP_TASKsystem task passes user-controlled URIs directly torestTemplate.exchange()with no restrictions on what hosts can be reached. This enables Server-Side Request Forgery (SSRF): anyone who can define or modify a workflow can instruct the Conductor server to make HTTP requests to internal infrastructure.CodeQL Alert #2 ·
http-task/.../HttpTask.java:175· severity: errorThe Problem
There is no validation of
input.getUri()before the call. An attacker with access to workflow definition APIs can target:http://169.254.169.254/latest/meta-data/(AWS IMDSv1, GCP, Azure) to steal instance credentialshttp://10.x.x.x/,http://192.168.x.x/,http://172.16-31.x.x/http://localhost:8080/api/admin/...(Conductor's own admin API)http://internal-db-host:5432/Why This Is By-Design — and Still a Problem
The HTTP task is intentionally designed to call external endpoints — that's its entire purpose. The issue is the absence of any configurable guard rails. Most production deployments need to reach external services, but should not allow the Conductor server itself to become a proxy into its own internal network.
Proposed Solution
Add a configurable
HttpTaskPropertiesclass (or extend existing config) with:127.0.0.0/8), link-local (169.254.0.0/16), and::1conductor.system-task.http.allowed-hosts): explicit patterns that override the block list for legitimate internal callsconductor.system-task.http.denied-hosts): additional patterns to block beyond defaultshttpCall(), beforerestTemplate.exchange()is calledExample config:
Threat Model Note
Risk is higher in multi-tenant or externally-accessible Conductor deployments where untrusted parties can submit workflow definitions. In fully internal, trusted-user-only deployments the practical risk is lower, but the fix is still correct defense-in-depth.
References