Skip to content

Back to the catalog

The Masked Namespace Vulnerability In Temporal CVE-2025-14986 | depthfirst
depthfirst.comwriteup

The Masked Namespace Vulnerability In Temporal CVE-2025-14986 | depthfirst

CVE-2025-14986 is an identity-binding flaw in Temporal's ExecuteMultiOperation endpoint. The outer request was authorized for one namespace, but inner StartWorkflow operations carried a different namespace that the server used for policy and schema preparation while persisting under the authorized one. The post shows the Go code, two exploits (cross-tenant schema access and policy bypass), and the v1.27 fix, with timeline December 2025 to January 2026.

TL;DR Explains how Temporal's ExecuteMultiOperation trusted an inner namespace over the authorized outer one, enabling cross-tenant and policy-bypass attacks, fixed in December 2025.
Document

What it is

CVE-2025-14986 is an identity-binding bug in the ExecuteMultiOperation handler of Temporal Server, found by a depthfirst researcher. The endpoint runs a StartWorkflow and an UpdateWorkflow in one call. Authorization checked only the outer request namespace, while the inner StartWorkflow carried its own Namespace field that the server also used.

How it works

ExecuteMultiOperation in service/frontend/workflow_handler.go authorizes the outer namespace and resolves a namespaceID. It passes that ID to convertToHistoryMultiOperationItem. That function then does two things with different identities:

  • It calls prepareStartWorkflowRequest(startReq), which derives policies, aliases and schema from the untrusted inner startReq.Namespace.
  • It builds the history request with common.CreateHistoryStartWorkflowRequest(namespaceID.String(), startReq, ...), so routing and persistence use the verified outer ID.

The result is a confused deputy. A request authorized for AttackerNS with an inner "namespace": "VictimNS" is validated against the victim's configuration but stored under the attacker's namespace.

flowchart LR
    R[Request: outer AttackerNS, inner VictimNS] --> A[Authz on outer namespace: passes]
    A --> P[Prepare: policy and schema from inner VictimNS]
    A --> S[Persist: under outer AttackerNS]
    P --> S

The page describes two exploits:

  • Cross-tenant schema access. The author created a VictimNS with private custom Search Attributes. A request as AttackerNS naming VictimNS was validated against that private schema, and the result was saved in the attacker's namespace. The page's impact claim is that Temporal read the victim's configuration to process the attacker's request.
  • Bring your own policy. A user authorized for a governed CorporateNS names a permissive PersonalNS in the inner payload. The workflow runs in the corporate namespace but is checked against the personal namespace's rules, such as execution timeouts, retry limits and archival settings. The page says this lets a developer override admin-set controls.

Preconditions / Affected

  • The attacker needs valid authentication and authorization for some namespace on the server, and must be able to call ExecuteMultiOperation.
  • The attacker must know the name of the target namespace.
  • The multi-tenant and governed-namespace scenarios matter most. The page does not describe an impact on single-namespace deployments.
  • Fixed releases are Temporal Server v1.27.x, 1.28.x and 1.29.x, released 30 December 2025. The page does not list the first vulnerable version.

What to do

Upgrade to a patched v1.27.x, 1.28.x or 1.29.x release. The fix adds a check before any processing, rejecting the request with errMultiOpNamespaceMismatch:

if startReq := op.GetStartWorkflow(); startReq != nil {
    // [FIX] Validate that inner namespace matches outer authorized namespace
    if startReq.Namespace != "" && startReq.Namespace != namespaceName.String() {
        return nil, "", errMultiOpNamespaceMismatch
    }
    // ...
}

The page gives no workaround and no detection guidance. One inference from the mechanism, not stated by the page: ExecuteMultiOperation calls whose inner namespace differs from the outer one would indicate attempts.

Caveats

The page shows no exploit output, only the request shape and the author's description of the results. The patch commit is cited as cd79be6. Disclosure ran from the report on 12 December 2025, through the patch on 16 December and fix validation on 18 December, to public release on 30 December 2025.

Organisations named here

  • depthfirst

CVEs named here

  • CVE-2025-14986

Technologies named here

  • Temporal
  • Go

Techniques named here

  • Confused deputy attack
  • Confused deputy
  • Bring Your Own Policy attack
  • Cross-tenant isolation breach