Temporal's frontend failed to cross-check the namespace of an internal 'embedded' request against the outer wrapper request. An attacker could wrap a `StartWorkflow` command claiming to be for 'Namespace B' (high limits) inside a request authorized for 'Namespace A' (low limits). The server validated against B but executed in A, effectively bypassing namespace-level constraints.
A logic flaw in Temporal's `ExecuteMultiOperation` API allowed authenticated users to execute workflows in one namespace while validating them against the policies of another. By embedding a request with a mismatched namespace ID, attackers could bypass rate limits and feature gates.
Temporal is the engine that keeps the internet's state machines running. It’s complex, powerful, and usually, pretty strict about who does what. Recently, Temporal introduced ExecuteMultiOperation—a power-user feature designed to execute multiple commands (like starting a workflow and sending a signal) in a single, atomic gRPC call. It’s a performance optimization for high-throughput systems that need to reduce round-trips.
But here’s the thing about batch operations: they introduce complexity in validation. When you hand the bouncer a stack of IDs for your group, does he check every single one against the guest list, or does he just glance at the top one and wave you all through?
In CVE-2025-14986, it turns out the bouncer was a bit confused. He was checking the ID of the person inside the trench coat, but letting the person wearing the trench coat into the club based on that ID. This created a fascinating logic gap where policy checks (rate limits, feature flags) were decoupled from execution targets.
The vulnerability lies in the ExecuteMultiOperation API handler. This handler accepts a request object that wraps a list of operations. Crucially, the wrapper has a Namespace field (used for routing and authorization), and the embedded operations (like StartWorkflowExecutionRequest) also have their own Namespace fields.
Logic dictates that these should match. If I authenticate to Namespace-A, I shouldn't be able to submit an embedded command for Namespace-B. However, the code responsible for validating the request—checking if the namespace has enough rate limit quota remaining or if a specific beta feature is enabled—looked at the embedded namespace.
Meanwhile, the code responsible for executing the logic (creating the workflow row in the database) looked at the outer namespace.
This is a classic 'Object of Check vs. Object of Use' vulnerability. The system validated the rules for the decoy namespace but applied the effects to the target namespace.
Let's look at what the logic likely resembled before the fix. The handler iterates over the operations to perform pre-execution checks.
Vulnerable Logic (Conceptual):
func (h *Handler) ExecuteMultiOperation(ctx context.Context, req *workflow.ExecuteMultiOperationRequest) ... {
// 1. Authorize against the OUTER namespace (Correct)
if !h.authorize(ctx, req.Namespace) {
return Error("Unauthorized")
}
// 2. Iterate over operations to validate limits/gates
for _, op := range req.Operations {
// BUG: Validating against the INNER namespace provided in the op!
// If op.Namespace is "Enterprise-Tier", we get high limits.
if !h.validateRateLimits(op.Namespace) {
return Error("Rate limit exceeded")
}
}
// 3. Execute in the OUTER namespace
return h.engine.ExecuteMulti(ctx, req.Namespace, req.Operations)
}Because the validateRateLimits function trusted the namespace string inside the operation struct, the attacker controlled the policy context completely independent of their execution context.
The Fix (PR #8839):
The remediation was simple but critical: enforce that op.Namespace == req.Namespace.
for _, op := range req.Operations {
if op.Namespace != req.Namespace {
return Error("Namespace mismatch: Inner operation must match outer request")
}
// ... proceed with validation
}To exploit this, we don't need memory corruption or complex heap spraying. We just need to speak gRPC. An attacker with access to a low-tier namespace (let's call it FreeTier-NS) wants to run a heavy workload that usually gets throttled.
They construct a ExecuteMultiOperationRequest:
FreeTier-NS (Where they have valid credentials).StartWorkflowExecutionRequest.Enterprise-NS (A namespace known to have high throughput limits or specific feature flags enabled).The Attack Chain:
FreeTier-NS. Pass.Enterprise-NS. It checks the Enterprise-NS bucket. Pass (it has plenty of capacity).FreeTier-NS context from the outer wrapper.The CVSS score of 1.3 (Low) suggests this is barely a nuisance. And strictly speaking, from a CIA (Confidentiality, Integrity, Availability) triad perspective, it is minor. You cannot read data from other namespaces. You cannot write data to namespaces you don't own.
However, in a multi-tenant SaaS environment, Policy is Money.
If Temporal is being offered as a managed service, this bug allows a tenant on the $5/month plan to utilize the resources and throughput of the $5000/month plan. It breaks the business logic of tenancy isolation, even if it preserves the data integrity of tenancy. Furthermore, it allows bypassing Feature Gates. If a feature is disabled in your namespace because it's buggy or security-sensitive, you might be able to toggle it on by masquerading as a namespace that has it enabled.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:U/S:N/AU:Y/R:U/RE:L/U:Green| Product | Affected Versions | Fixed Version |
|---|---|---|
Temporal Server Temporal Technologies | >= 1.24.0, < 1.27.4 | 1.27.4 |
Temporal Server Temporal Technologies | >= 1.28.0, < 1.28.2 | 1.28.2 |
Temporal Server Temporal Technologies | >= 1.29.0, < 1.29.2 | 1.29.2 |
| Attribute | Detail |
|---|---|
| CWE | CWE-863 (Incorrect Authorization) |
| CVSS v4.0 | 1.3 (Low) |
| Vector | CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N |
| Attack Vector | Network (gRPC) |
| Exploit Complexity | Low |
| Privileges Required | Low (Valid Namespace Access) |
The software performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
Get the latest CVE analysis reports delivered to your inbox.