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]

Reply via email to