Temporal write access can run shell on your Worker Service host
How to fix CVE-2026-89139: upgrade Temporal Server to 1.31.3 or 1.30.7
Contents
Anyone with write access in a single Temporal namespace can make the Worker Service host run a shell command of their choosing. Temporal published CVE-2026-89139 today (CVSS 4.0 8.7 High). The Worker Controller's built-in subprocess compute provider takes the program and argv from the caller's worker-deployment request, not from operator config, and runs it immediately on the Worker Service machine. That process holds persistence credentials for every namespace and the cluster TLS material, so one namespace write reaches the whole cluster.
Ship the same upgrade for the sibling admin-callback bug CVE-2026-87858 (CVSS 4.0 7.2 High): a caller-controlled source header on a completion callback can retarget the History service at the internal frontend as system administrator. Do not open a second article for that train. This is the operator write-up; the HOL Guard evidence packs for CVE-2026-89139 and CVE-2026-87858 are the source records.
What breaks
On CVE-2026-89139, Temporal Server 1.31.0 through before 1.31.3 ships a Worker Controller Instance module inside the Worker Service. That module registers a compute provider named subprocess. An authenticated caller with only a write role in one namespace can set a worker deployment version whose scaling group uses that provider. The handler validates the spec, then invokes every provider with the invoke strategy right away. No scaling event, task arrival, or unusual request sequence is required. The official temporal-server binaries and container images include the provider.
The only gate that can keep subprocess unreachable is the per-namespace dynamic config workercontroller.compute_providers.enabled. Its default is an unset list, and the allowlist check is skipped when the value is unset, so every registered provider is permitted. The separate workercontroller.enabled flag defaults to false and does not gate this path. Temporal confirmed an affected release with that setting never present anywhere in dynamic config is still exposed.
On CVE-2026-87858, History decided whether a Workflow completion callback was "internal" by reading a caller-supplied HTTP header named source. A namespace writer who can attach a callback whose host matches component.callbacks.allowedAddresses, and who can put a non-empty source header on it (releases 1.30.0+), causes History to rewrite only scheme and host and send the caller's path, query, and body to the local frontend client. Where an internal frontend is deployed with its HTTP API enabled, that client authorizes every request as system administrator. Confirmed effects include terminating Workflows in other namespaces, registering namespaces, changing another namespace's config, and deleting another namespace and its Workflows. The same routing exists in both HSM and CHASM callback delivery. Releases 1.25.0 through 1.29.7 need the header to exactly match a configured cluster ID (harder). Upstream patches: PR 12021 (auto-scaled-workers bump for the subprocess fix), auto-scaled-workers PR 129, and PR 11965 (make Nexus callback source header inspection opt-in via callback.inspectSourceHeader, default false).
Who is not in scope
You are not in the CVE-2026-89139 blast radius if your Temporal Server is older than 1.31.0, or you are already on 1.31.3 / 1.32.0+, or the Worker Service is not running (non-default topologies only), or every namespace's workercontroller.compute_providers.enabled is set to an explicit list that omits subprocess. Deployments with no authorizer already grant every caller every namespace, so they have no namespace boundary for this bug to cross. For CVE-2026-87858, stock static topology without an internal frontend HTTP port, or an empty component.callbacks.allowedAddresses (the default denies all external callback URLs), keeps the admin retarget closed. Temporal Cloud is a separate product; this write-up is about self-hosted Temporal Server.
What this is not
Neither CVE is unauthenticated internet RCE. Both need an authenticated Temporal principal with namespace write. CVE-2026-89139 is host command execution on the Worker Service under the server process account. CVE-2026-87858 is admin-equivalent state changes through the internal frontend, not a free remote shell by itself. Neither is listed on CISA KEV as of this writing.
One operator check
On every self-hosted cluster, run the server binary or image tag check first:
temporal-server --version
# or
docker inspect --format '{{.Config.Image}}' temporal-frontend
Treat 1.31.0, 1.31.1, and 1.31.2 as CVE-2026-89139-exposed until you are on 1.31.3 or 1.32.0. For the callback sibling, treat 1.30.0 through before 1.30.7 and 1.31.0 through before 1.31.3 the same way; fixed trains are 1.30.7, 1.31.3, and 1.32.0.
Then confirm the dangerous defaults are not still live while you schedule the upgrade:
# dynamic config (per namespace). Unset = every compute provider allowed, including subprocess.
# Prefer an explicit allowlist that omits subprocess until you patch.
# workercontroller.compute_providers.enabled
# callback allowlist empty by default (deny). Non-empty + internal-frontend httpPort > 0 = 87858 exposure window.
# component.callbacks.allowedAddresses
# services.internal-frontend.rpc.httpPort
To look for a subprocess config already attached, call DescribeWorkerDeploymentVersion for each worker deployment version in each namespace and check whether any scaling group's compute provider type is subprocess. For callbacks already attached, DescribeWorkflowExecution returns registered completion callbacks. Note the frontend HTTP API logs method and URL at debug only, so missing log lines are not proof the admin path was unused.
How to fix
Upgrade Temporal Server to 1.31.3 (or 1.30.7 on the 1.30 train, or 1.32.0+):
# Helm example. Pin the chart/app version that ships temporal-server 1.31.3 or 1.32.0.
helm upgrade temporal temporalio/temporal --version <chart-with-1.31.3-or-1.32.0>
# Container
# Use the official image tags that embed temporal-server 1.31.3 / 1.30.7 / 1.32.0
Release notes: v1.30.7, v1.31.3, v1.32.0. After upgrade, re-check temporal-server --version, confirm no worker deployment version still advertises provider type subprocess unless you intentionally allow it post-patch, and leave callback.inspectSourceHeader at its patched default (false) unless you are in a documented mixed-version escape hatch that still needs legacy HTTP worker callbacks.
References
- NVD CVE-2026-89139 (CVSS 4.0 8.7 High)
- NVD CVE-2026-87858 (CVSS 4.0 7.2 High)
- temporal PR 12021 / auto-scaled-workers PR 129
- temporal PR 11965 (callback source header opt-in)
- HOL Guard packs: CVE-2026-89139, CVE-2026-87858
Continue reading
All posts
BREAKING: Unbound DNSKEY digest overflow can RCE your resolver (1.26.1)
How to fix CVE-2026-81642: upgrade Unbound to 1.26.1

BREAKING: CVE-2026-0310 PAN-OS XML overflow gives unauth root on PA-Series
How to fix CVE-2026-0310: upgrade PAN-OS to the fixed hotfix for your train (for example 12.2.3, 12.1.10, 11.2.13-h2, 11.1.16-h2, 10.2.18-h10). Unauth XML to management web or dataplane can root PA-Series firewalls.

CVE-2026-75021: fastify-cli debug-host bind can expose Inspector RCE
How to fix CVE-2026-75021: upgrade fastify-cli to 8.0.1
