icysun opened a new issue, #18342: URL: https://github.com/apache/dolphinscheduler/issues/18342
# Unauthenticated RCE via Worker Netty RPC (`IPhysicalTaskExecutorOperator.dispatchTask`) — Default `0.0.0.0` bind, no auth ## Summary DolphinScheduler Worker nodes expose the Netty RPC endpoint `IPhysicalTaskExecutorOperator.dispatchTask` on **`0.0.0.0:1234`** by default, with **no authentication, no authorization, no TLS, no IP allowlist, and no input validation**. Any TCP client that can reach the Worker port can invoke `dispatchTask` with an attacker-controlled `TaskExecutionContext` (`taskType=SHELL`, arbitrary `rawScript`), causing **arbitrary OS command execution on the Worker host** — which runs as **root** in the official standalone Docker image. **This was reported privately to `[email protected]` on 2026-06-10.** The DolphinScheduler security team declined to treat it as a vulnerability, stating that internal RPC communication falls outside the project's threat model (see rationale below). I respectfully disagree with this assessment and am disclosing publicly so that the community and operators can make their own informed decisions. ## Impact - **Pre-auth RCE**: No credentials, no session, no project/tenant binding required. A single TCP connection to port 1234 is sufficient. - **Runs as root**: The official `apache/dolphinscheduler-standalone-server:dev` Docker image runs as `uid=0` (root). - **Default exposure**: `WorkerConfig.listenPort=1234`, `NettyServerConfig` does not set `listenHost`, `NettyRemotingServer` binds to `INADDR_ANY` (`0.0.0.0`). - **Reachability**: - **Standalone mode** (common for dev/test and small productions): port 1234 is directly reachable from any network the host is connected to. - **K8s/cluster mode**: Worker binds to Pod IP. An attacker needs a Pod foothold or a misconfigured NetworkPolicy. Still, lateral movement within a cluster is a real threat. ## Code Location | File | Line | Issue | |------|------|-------| | `dolphinscheduler-extract/.../base/server/NettyRemotingServer.java` | ~L108 | `serverBootstrap.bind(serverConfig.getListenPort())` — no host specified = `INADDR_ANY` | | `dolphinscheduler-extract/.../base/server/NettyServerConfig.java` | — | No `listenHost` field; defaults to all interfaces | | `dolphinscheduler-task/.../PhysicalTaskExecutorOperatorImpl.java` | `dispatchTask` | Accepts arbitrary `TaskExecutionContext`, executes `rawScript` via `OSUtils.exeShell()` with zero validation | | `dolphinscheduler-spi/.../utils/OSUtils.java` | `exeShell` | Shell execution sink | ## Why I Believe This Is a Vulnerability The security team's response references DolphinScheduler's "trusted environment" security model. However: 1. **Default `0.0.0.0` binding is a code-level defect.** If the intent is "only trusted networks should reach this port," the default should be `127.0.0.1` (loopback), requiring operators to explicitly opt into external binding. The current default is the opposite — wide open by default, locked down only if the operator knows to change it. 2. **"Trusted control-plane" does not justify zero defense-in-depth.** Comparable systems (Hadoop, Kubernetes, Spark, Flink) all implement token-based auth or mTLS on their internal RPC channels. DolphinScheduler's Worker RPC has none. 3. **The official Docker image runs as root.** Combined with default `0.0.0.0` binding, this means out-of-the-box deployments have a network-accessible root shell. 4. **Standalone mode is a supported, documented deployment.** It is not a "misconfiguration" — it is the default quick-start path that many users follow into production. ## CVSS **Standalone-server deployment:** - CVSS v3.1: 9.8 — `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` - CVSS v4.0: 9.3 — `AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N` **K8s / cluster deployment:** - CVSS v3.1: 9.3 — `AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` - CVSS v4.0: 8.6 — `AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N` ## End-to-End Verification Verified against `apache/dolphinscheduler-standalone-server:dev` (master @ c9e373e) on 2026-06-10: ```bash $ python3 poc_dolphinscheduler_worker_rpc_rce.py \ --target 127.0.0.1 --port 1234 \ --command "touch /tmp/pwned_rpc_rce && id > /tmp/rpc_rce_id.txt" [+] Connected to 127.0.0.1:1234 [+] Sent dispatchTask request (opaque=1) [+] Response body: {"success":true,"body":"eyJkaXNwYXRjaFN1Y2Nlc3MiOnRydWUsIm1lc3NhZ2UiOm51bGx9"} $ docker exec ds-standalone cat /tmp/rpc_rce_id.txt uid=0(root) gid=0(root) groups=0(root) ``` ## Suggested Fix Minimal one-line fix (backward compatible — operators who need external binding set it explicitly): ```java // NettyServerConfig.java private String listenHost = "127.0.0.1"; // default to loopback instead of INADDR_ANY // NettyRemotingServer.java serverBootstrap.bind(serverConfig.getListenHost(), serverConfig.getListenPort()).sync(); ``` Additional defense-in-depth: 1. Add token-based auth or mTLS for the Worker RPC channel 2. Validate `tenantCode` against a server-side allowlist in `dispatchTask` 3. Run Worker as a non-root user in the official Docker image ## Workarounds for Operators If you're running DolphinScheduler now: - **Restrict network access** to port 1234 (firewall rules / K8s NetworkPolicy) - **Docker**: Use `--network=host` only on trusted networks; otherwise map port 1234 to `127.0.0.1:1234` - **K8s**: Ensure NetworkPolicy denies ingress to Worker pods on port 1234 from outside the namespace ## Disclosure Timeline | Date | Event | |------|-------| | 2026-06-09 | Vulnerability discovered, end-to-end PoC verified | | 2026-06-10 | Reported privately to `[email protected]` | | 2026-06-12 | DolphinScheduler security team declined CVE ("outside threat model") | | 2026-06-12 | Public disclosure (this issue) | Standard 90-day window was offered. Given the team's position that no fix is warranted, I am disclosing to ensure operators are aware of the risk. ## Discoverer **IcySun** ([email protected]) Manual code review and verification completed. PoC available upon request to verified security researchers. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
