Authorize the manual workflow run endpoint

fix(workflow): authorize the manual workflow run endpoint
Authorize the manual workflow run endpointeafd72-fix-authorize-the-manual-workflow-run-endpoint-cve-2026-35053fixauthorize manual workflow run endpoint

Committed by nawazdhandala

commit message
fix(workflow): authorize the manual workflow run endpoint

GHSA-6c3w-7xg4-4cf7 / CVE-2026-35053 reported GET/POST
/workflow/manual/run/:workflowId as having no authentication. The patch
added UserMiddleware.getUserMiddleware to both routes, but that
middleware is a context loader rather than a gate: with no cookie, no
bearer token and no apikey header it tags the request UserType.Public
and calls next(). The handler never inspected userType, and
QueueWorkflow.addWorkflowToQueue is not passed the request, so it could
not check the caller either. A credential-less request still reached the
queue and scheduled the workflow (GHSA-v8v9-p6ff-jwmm).
 
Authorize in the handler, following the pattern already used for the
other project-scoped custom routes (MonitorAPI /refresh-status,
WorkspaceNotificationRuleAPI /test):
 
- assertAuthenticatedProjectMember rejects Public callers.
- The owning project is read off the workflow row (as root) and matched
  against the caller's project, so a member of project A cannot reach
  project B's workflow id by sending their own tenantid header. A
  workflow that does not exist is rejected identically, so the route is
  not an id oracle.
- Running a workflow executes its components (arbitrary JavaScript,
  notification sends, resource create/delete), so it is gated on the
  Workflow model's own update permissions rather than mere membership.
 
Programmatic callers are unaffected: they trigger a workflow through its
own /workflow/trigger/:secretkey route, authenticated by the workflow's
secret key.
 
The dashboard's Run button used a raw API.post that sent no tenantid
header, so it now sends ModelAPI.getCommonHeaders().
 
Adds App/Tests/FeatureSet/Workflow/ManualWorkflowRunAuth.test.ts, which
had no coverage before. 17 of its 30 tests fail against the pre-fix
handler, including the advisory's credential-less POST proof of concept.

Editor assessment

This commit patches CVE-2026-35053. The subject is short and accurate; the body is a model of security reasoning. It recounts that the first patch added a middleware which merely tags requests as Public and calls next, so a credential-less request still queued a workflow, then explains how the handler rejects Public callers, reads the owning project from the workflow row as root to prevent cross-tenant access by header, and rejects nonexistent workflows identically so the route is not an id oracle. It justifies gating on the workflow's update permissions because runs execute arbitrary JavaScript and notifications. The test evidence - seventeen of thirty failing pre-fix, including the advisory proof of concept - is unusually concrete.

Browse categories

More fix examples · Back to search