You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Update completion wait_timeout_seconds is caller-unbounded #775
Defect (published Server 2.11.1, Workflow 2.10.2, and native)
An update submitted with wait_for: completed waits up to the caller's wait_timeout_seconds. That field validates only nullable|integer|min:1, on POST /api/workflows/{id}/update/{name} and on bridge update_workflow targets. UpdateWaitPolicy::requestedTimeoutSeconds (Workflow 2.10.2) returns any positive integer unchanged, and DW_V2_UPDATE_WAIT_COMPLETION_TIMEOUT_SECONDS is only the default when the field is absent. So one request can hold a server worker, or in native a request task, for as long as it asks while the update stays incomplete.
Native matches PHP here (updates.rs: timeout.unwrap_or(self.update_wait_seconds)). It holds no transaction or pool connection while it waits, only the request and a wake subscription. PHP holds a request worker for the whole wait.
Found while preparing the Rust bridge adapters review (#325), after Security's #773 review asked for every caller-controlled duration and count to be bounded server-side.
Expected
A documented server-side maximum for wait_timeout_seconds in the shared contract, applied at every ingress (update route, bridge update, any SDK-facing alias) before admission. A longer request is clamped or refused, with the choice documented, and covered by exact-boundary and above-boundary tests on both servers. The wait's own completion semantics are unchanged.
Security decision: use a documented 60-second maximum and refuse any larger wait_timeout_seconds with 422 before admission at every ingress. This aligns Server with the now-merged Workflow UpdateWaitPolicy::MAX_COMPLETION_TIMEOUT_SECONDS boundary. Cover 60 and 61 seconds on the regular update route, bridge update route, and every other accepted alias on both PHP and native paths.
Bound the effective configured default as well as request overrides. Workflow main now clamps completionTimeoutSeconds() to 60. Native config_audit::update_wait_completion_timeout_seconds currently applies only max(1), so a request without an override can still inherit an arbitrarily large value. Match PHP by clamping effective native configuration to 60 and cover configured 60/61 values.
Caller-supplied values above 60 remain a 422 before admission.
Exercise both regular aliases—POST /workflows/{id}/update/{name} and POST /workflows/{id}/runs/{runId}/update/{name}—plus bridge update.
Dependency caveat: the current Server head pins durable-workflow/workflow 2.13.1 at b2a3369110b8cbdf060802ff91e475110e66e333. The newly merged 60-second Workflow policy is not yet in that installed artifact, and its merge did not authorize a release or Server dependency update.
Make the Server PHP path safe independently now: validate caller values at 60 and clamp the application effective default to 60, or use an explicitly qualified dependency update through the normal release path. Acceptance must run against the package actually pinned and installed by Server; Workflow main alone is not runtime evidence.
Activity
rmcdaniel commentedon Oct 26, 2026
Security decision: use a documented 60-second maximum and refuse any larger
wait_timeout_secondswith 422 before admission at every ingress. This aligns Server with the now-merged WorkflowUpdateWaitPolicy::MAX_COMPLETION_TIMEOUT_SECONDSboundary. Cover 60 and 61 seconds on the regular update route, bridge update route, and every other accepted alias on both PHP and native paths.rmcdaniel commentedon Oct 26, 2026
Acceptance refinement from the exact sources:
completionTimeoutSeconds()to 60. Nativeconfig_audit::update_wait_completion_timeout_secondscurrently applies onlymax(1), so a request without an override can still inherit an arbitrarily large value. Match PHP by clamping effective native configuration to 60 and cover configured 60/61 values.POST /workflows/{id}/update/{name}andPOST /workflows/{id}/runs/{runId}/update/{name}—plus bridge update.rmcdaniel commentedon Oct 26, 2026
Dependency caveat: the current Server head pins
durable-workflow/workflow2.13.1 atb2a3369110b8cbdf060802ff91e475110e66e333. The newly merged 60-second Workflow policy is not yet in that installed artifact, and its merge did not authorize a release or Server dependency update.Make the Server PHP path safe independently now: validate caller values at 60 and clamp the application effective default to 60, or use an explicitly qualified dependency update through the normal release path. Acceptance must run against the package actually pinned and installed by Server; Workflow
mainalone is not runtime evidence.Bound the update wait on update-bound service operations too (#775)
Enforce the update wait ceiling at update admission (#775)
Merge pull request #778 from durable-workflow/fix/775-update-wait-max…
Merge branch 'fix/775-update-wait-maximum' (#775) into rust-325-bridg…
WIP: native follows published 2.11.3 on repair-pass and service-call …
Follow Core 2.14 on the repair report, service-call wait and idempote…