From 33032ed297cf9ea867388d4ea2ece607c9d36dc7 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 30 Mar 2026 10:54:18 +0000 Subject: [PATCH] fix: enforce workspace isolation on flow resume endpoint (#8612) Co-authored-by: Claude Opus 4.5 --- backend/windmill-api/src/jobs.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 461eb9da5d..18284c2a21 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -2179,13 +2179,25 @@ async fn list_jobs( pub async fn resume_suspended_flow_as_owner( authed: ApiAuthed, Extension(db): Extension, - Path((_w_id, flow_id)): Path<(String, Uuid)>, + Path((w_id, flow_id)): Path<(String, Uuid)>, QueryOrBody(value): QueryOrBody, ) -> error::Result { let mut tx = db.begin().await?; let (flow, job_id, is_wac) = get_suspended_flow_info(flow_id, &mut tx).await?; + // Verify the job belongs to this workspace + let job_workspace: Option = + sqlx::query_scalar("SELECT workspace_id FROM v2_job WHERE id = $1") + .bind(&flow.id) + .fetch_optional(&mut *tx) + .await?; + if job_workspace.as_deref() != Some(w_id.as_str()) { + return Err(Error::NotFound( + "Job not found in this workspace".to_string(), + )); + } + let flow_path = flow.script_path.as_deref().unwrap_or_else(|| ""); require_owner_of_path(&authed, flow_path)?; check_scopes(&authed, || format!("jobs:run:flows:{}", flow_path))?;