GHSA-46R4-Q7WV-32FC
Vulnerability from github – Published: 2026-10-21 16:29 – Updated: 2026-10-21 16:29Summary
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.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/openchoreo/openchoreo"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.0.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/openchoreo/openchoreo"
},
"ranges": [
{
"events": [
{
"introduced": "1.1.0"
},
{
"fixed": "1.1.7"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/openchoreo/openchoreo"
},
"ranges": [
{
"events": [
{
"introduced": "1.2.0"
},
{
"fixed": "1.2.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-113727"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-21T16:29:53Z",
"nvd_published_at": "2026-10-20T22:19:29Z",
"severity": "HIGH"
},
"details": "## Summary\n\nThe 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.\n\nA `WorkflowRun`\u0027s 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.\n\nThe 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.\n\n## Impact\n\nRewriting 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:\n\n- Read the victim\u0027s 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.\n- Read the run\u0027s Kubernetes events.\n- Delete the run.\n\nSo 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.\n\nExploitation requires an authenticated caller with an `AuthzRoleBinding` or `ClusterAuthzRoleBinding` granting `workflowrun:update` at project or component scope in the victim\u0027s namespace, plus knowledge of the target run\u0027s name. An anonymous caller cannot reach this.\n\n## Patches\n\nThe 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.\n\n| Line | Affected | Fixed in |\n|---|---|---|\n| 1.0.x | 1.0.0 through 1.0.5 | 1.0.6 |\n| 1.1.x | 1.1.0 through 1.1.6 | 1.1.7 |\n| 1.2.x | 1.2.0 through 1.2.4 | 1.2.5 |\n\nUpgrade to the patched release on your line. No configuration change is needed after upgrading.\n\n## Workarounds\n\nIf you cannot upgrade immediately, restrict who holds `workflowrun:update`.\n\nAudit 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.\n\nTreat any credential bound to `workload-publisher` as privileged. CI systems are the usual holder, and a leaked CI token is enough to run this.",
"id": "GHSA-46r4-q7wv-32fc",
"modified": "2026-10-21T16:29:53Z",
"published": "2026-10-21T16:29:53Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/security/advisories/GHSA-46r4-q7wv-32fc"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-113727"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/pull/4596"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/pull/4618"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/pull/4626"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/pull/4627"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/commit/0e311468bb704b0dce7753b89c9d0204009285ca"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/commit/477031c6fece0666f144942fb02c0b579dacc0bb"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/commit/91e1e868eb8e0e67274109018d00a767b22eda14"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/commit/d5ed0ef62d9c9af7b05a72aed2bcbc0ac9d45426"
},
{
"type": "PACKAGE",
"url": "https://github.com/openchoreo/openchoreo"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/releases/tag/v1.0.6"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/releases/tag/v1.1.7"
},
{
"type": "WEB",
"url": "https://github.com/openchoreo/openchoreo/releases/tag/v1.2.5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L",
"type": "CVSS_V3"
}
],
"summary": "OpenChoreo: Authorization bypass on WorkflowRun update allows cross-project takeover of workflow runs"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.