---
id: "CVE-2026-113727"
kind: "vulnerability"
aliases: ["CVE-2026-113727", "GHSA-46r4-q7wv-32fc"]
title: "OpenChoreo: Authorization bypass on WorkflowRun update allows cross-project takeover of workflow runs"
severity: "high"
cvss: 7.400000095367432
epss: 0.004339999984949827
exploited: false
status: "open"
category: "other"
products: [{"name": "github.com/openchoreo/openchoreo", "fixed": ["1.0.6"], "affected": ">= 1.0.0, < 1.0.6", "ecosystem": "go"}, {"name": "github.com/openchoreo/openchoreo", "fixed": ["1.1.7"], "affected": ">= 1.1.0, < 1.1.7", "ecosystem": "go"}, {"name": "github.com/openchoreo/openchoreo", "fixed": ["1.2.5"], "affected": ">= 1.2.0, < 1.2.5", "ecosystem": "go"}]
ecosystems: ["go"]
tags: ["ci", "cwe-639", "kubernetes", "openchoreo", "other", "self-hosted"]
not_affected_if: ["no-workflowrun-update-grants", "version-1.3-or-later"]
published_at: "2026-10-20T22:19:29+00:00"
first_seen_at: "2026-10-23T19:11:32+00:00"
updated_at: "2026-10-23T21:57:25+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-46r4-q7wv-32fc", "first_seen_at": "2026-10-23T19:11:32+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-113727", "first_seen_at": "2026-10-23T21:57:25+00:00"}]
---

# OpenChoreo: Authorization bypass on WorkflowRun update allows cross-project takeover of workflow runs

OpenChoreo's API server checked authorization for updating a WorkflowRun against labels from the request body instead of the stored object, so a caller with workflowrun:update on one component could rewrite another project's run and take over its ownership labels. That grants read access to the victim's build logs and events and the ability to delete the run.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- go:github.com/openchoreo/openchoreo affected >= 1.0.0, < 1.0.6 fixed 1.0.6
- go:github.com/openchoreo/openchoreo affected >= 1.1.0, < 1.1.7 fixed 1.1.7
- go:github.com/openchoreo/openchoreo affected >= 1.2.0, < 1.2.5 fixed 1.2.5

## How to check

Check the OpenChoreo version in use (go module github.com/openchoreo/openchoreo) and whether it falls in 1.0.0-1.0.5, 1.1.0-1.1.6, or 1.2.0-1.2.4.
Audit AuthzRole and ClusterAuthzRole objects for workflowrun:update, including the shipped workload-publisher role and any admin wildcard grants.

## Fix

Upgrade to 1.0.6, 1.1.7, or 1.2.5 on your release line; no configuration change is needed.
Until then, remove workflowrun:update from roles granted to untrusted principals and treat CI tokens bound to workload-publisher as privileged.

## Timeline

- 2026-10-23T19:11:32+00:00 ghsa https://github.com/advisories/GHSA-46r4-q7wv-32fc
- 2026-10-23T21:57:25+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-113727

## From the sources

## Summary

The OpenChoreo API server authorized `PUT .../workflowruns/{runName}` against ownership metadata taken from the request body, while the object it actually mutated was selected by the URL path. Nothing forced the two to agree.

A `WorkflowRun`'s membership in a project and component is carried entirely by its `openchoreo.dev/project` and `openchoreo.dev/component` labels. Because the `workflowrun:update` check read those labels from the submitted object rather than the stored one, a caller holding `workflowrun:update` on one component could name a run belonging to a different project or component in the URL, supply labels for the component they legitimately control, pass the check, and have the unrelated run rewritten with their own ownership labels.

The namespace is taken from the URL and feeds both the authorization check and the Kubernetes read, so it cannot diverge. This is cross-project and cross-component escalation inside a single namespace, not a cross-tenant issue.

## Impact

Rewriting the ownership labels transfers authority over the run. Every other WorkflowRun check (view, logs, events, status, delete, list) derives its scope from the stored labels, so once the write lands the policy engine legitimately grants the attacker access to an object they never had rights to. They can then:

- Read the victim's build logs. These stream raw pod logs from the workflow plane and routinely carry source paths, registry destinations, and credentials a build step echoed by accident.
- Read the run's Kubernetes events.
- Delete the run.

So the primary impact is confidentiality and availability, not only integrity. On the integrity side, `spec.workflow.parameters` can be overwritten on a pending run, and manipulating the two ownership labels can either wedge the run in a permanent `ComponentValidationFailed` condition or downgrade it to a standalone run that skips component validation.

Exploitation requires an authenticated caller with an `AuthzRoleBinding` or `ClusterAuthzRoleBinding` granting `workflowrun:update` at project or component scope in the victim's namespace, plus knowledge of the target run's name. An anonymous caller cannot reach this.

## Patches

The authorization check now loads the stored WorkflowRun and derives every ownership attribute from it instead of from the request body. Separately, the `openchoreo.dev/project` and `openchoreo.dev/component` labels are now immutable on update, so an authorized caller cannot hand their own run to another project either.

| Line | Affected | Fixed in |
|---|---|---|
| 1.0.x | 1.0.0 through 1.0.5 | 1.0.6 |
| 1.1.x | 1.1.0 through 1.1.6 | 1.1.7 |
| 1.2.x | 1.2.0 through 1.2.4 | 1.2.5 |

Upgrade to the patched release on your line. No configuration change is needed after upgrading.

## Workarounds

If you cannot upgrade immediately, restrict who holds `workflowrun:update`.

Audit your `AuthzRole` and `ClusterAuthzRole` definitions for that action and remove it from any role granted to principals you would not trust with write access to every workflow run in the namespace. Among the roles shipped with OpenChoreo, only the system role `workload-publisher` lists `workflowrun:update` explicitly, and `admin` holds it through its `*` wildcard. Custom roles in your own values file may also include it, so check those.

Treat any credential bound to `workload-publisher` as privileged. CI systems are the usual holder, and a leaked CI token is enough to run this.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
