{"id":"CVE-2026-73293","revision":null,"records":[{"revision":"f1fff2624eca41faad017b16d7c6c950","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-73293","aliases":[],"title":"Semaphore UI: Manager-to-owner privilege escalation via custom-role slug collision","description":"Semaphore UI is a web interface for managing DevOps tools.  Prior to 2.18.19 and from 2.19.0-alpha3 until 2.19.5-beta5, ProjectMiddleware and GetProjectOrGlobalRoleBySlug allow a project manager to use POST /api/project/{id}/roles to create a custom manager role with permission bitmask 15, overriding the built-in manager permissions and granting CanUpdateProject and CanManageProjectUsers owner capabilities. This issue is fixed in versions 2.18.19 and 2.19.5-beta5.","state":0,"publishedAt":"2026-08-12T15:45:22.145+00:00","modifiedAt":"2026-08-12T16:56:45.324+00:00","affected":[{"ecosystem":"Vendor product","name":"semaphore","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"semaphoreui\",\n                    \"product\": \"semaphore\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 2.18.19\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 2.19.0-alpha3, < 2.19.5-beta5\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":8.8,"severity":"HIGH"}],"references":["https://github.com/semaphoreui/semaphore/security/advisories/GHSA-cxvf-gvfq-36w2","https://github.com/semaphoreui/semaphore/commit/1c4bb65df114962134f8829d4a03667106a01a68","https://github.com/semaphoreui/semaphore/commit/bb2a4e1f08c8023e618f8dd6eaca73554f2c33bb","https://github.com/semaphoreui/semaphore/releases/tag/v2.18.19","https://github.com/semaphoreui/semaphore/releases/tag/v2.19.5-beta5"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-73293","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-73293","identifiers":["CVE-2026-73293"]},"retained":false,"historicalAffected":[]},{"revision":"6ab1dc34a518492883172787b2a4142a","observedAt":"2026-10-25T15:19:03.401+00:00","statement":{"source":"nvd","id":"CVE-2026-73293","aliases":[],"title":"Semaphore UI is a web interface for managing DevOps tools.  Prior to 2.18.19 and from 2.19.0-alpha3 until 2.19.5-beta5, ProjectMiddleware and GetProjectOrGlobalRoleBySlug allow a project manager to use POST /api/project/{id}/roles to create…","description":"Semaphore UI is a web interface for managing DevOps tools.  Prior to 2.18.19 and from 2.19.0-alpha3 until 2.19.5-beta5, ProjectMiddleware and GetProjectOrGlobalRoleBySlug allow a project manager to use POST /api/project/{id}/roles to create a custom manager role with permission bitmask 15, overriding the built-in manager permissions and granting CanUpdateProject and CanManageProjectUsers owner capabilities. This issue is fixed in versions 2.18.19 and 2.19.5-beta5.","state":0,"publishedAt":"2026-08-12T16:17:22.493+00:00","modifiedAt":"2026-10-24T15:10:00.19+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":8.8,"severity":"HIGH"}],"references":["https://github.com/semaphoreui/semaphore/commit/1c4bb65df114962134f8829d4a03667106a01a68","https://github.com/semaphoreui/semaphore/commit/bb2a4e1f08c8023e618f8dd6eaca73554f2c33bb","https://github.com/semaphoreui/semaphore/releases/tag/v2.18.19","https://github.com/semaphoreui/semaphore/releases/tag/v2.19.5-beta5","https://github.com/semaphoreui/semaphore/security/advisories/GHSA-cxvf-gvfq-36w2"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-73293","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-269"],"productCriteria":[],"sourceDates":{"published":"2026-08-12T16:17:22.493","lastModified":"2026-10-24T15:10:00.190"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-73293","identifiers":["CVE-2026-73293"]},"retained":false,"historicalAffected":[]},{"revision":"a1cecba982a446f19b01f68b4577d765","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-cxvf-gvfq-36w2","aliases":["CVE-2026-73293","GO-2026-6371"],"title":"Semaphore UI: Manager-to-owner privilege escalation via custom-role slug collision","description":"## Summary\n\nSemaphore resolves a project member's effective permissions in `ProjectMiddleware` by looking up a role row whose slug matches the member's assigned role, and overwrites the built-in permission bitmask with that row's value. A member holding the built-in `manager` role creates a custom project role through `POST /api/project/{id}/roles`, a route gated only by the `CanManageProjectResources` permission that `manager` already holds.\n\nThe role-creation validator does not reserve the built-in slug names (`owner`, `manager`, `task_runner`, `guest`) and sets no ceiling on the permission bits a caller may grant. A manager creates a role with slug `manager` carrying the full bitmask `15`, including the two owner-only bits `CanUpdateProject` and `CanManageProjectUsers` that `manager` does not hold. The slug lookup that backs permission resolution ignores project scope, so this attacker-created row is returned on the next request and the manager's effective permissions become owner-equivalent.\n\nResult: a project manager escalates to full owner of the project with one authenticated request, then adds or removes members, changes project settings, deletes the project, or demotes the legitimate owner.\n\n## Affected\n\nsemaphoreui/semaphore v2.18.12 (current latest as of 2026-06-09) and `develop` HEAD. Confirmed live-exploitable on v2.18.12 (commit 8a4dcf0); the affected files are unchanged on `develop` with no fix commit since the tag. Earlier releases that ship PRO custom project roles are likely affected but were not tested.\n\nRequires the PRO build (custom project roles). The official `semaphoreui/semaphore` Docker image ships this feature active by default, with no subscription or configuration flag.\n\nPure community builds without custom project roles are not affected: the role-creation endpoint returns 404 there.\n\n## Root cause\n\n`ProjectMiddleware` reads the member's built-in role permissions, then calls `GetProjectOrGlobalRoleBySlug` and, when a role row shares the member's role slug, replaces the effective permission bitmask with the database value (`api/projects/project.go:49-53`). `GetProjectOrGlobalRoleBySlug(projectID, slug)` accepts a project id but runs `select * from role where slug=?`, ignoring project scope (`db/sql/role.go:59-62`). `ValidateRole` checks only that the role name is non-empty, and enforces neither a reserved-slug list nor a permission ceiling (`db/Role.go:10-15`). The role-creation route `POST /api/project/{id}/roles` is gated by `CanManageProjectResources` (`api/router.go:294,354`), a bit the built-in `manager` role holds, while the actions it unlocks are gated by the owner-only `CanUpdateProject` and `CanManageProjectUsers` (`api/router.go:364,380`). A manager creates a row with slug `manager` and permissions `15`, and the next request resolves the manager's effective permissions to the owner bitmask.\n\n## Reproduction\n\nsemaphoreui/semaphore v2.18.12 Docker (official image, PRO build), default config, default roles.\n\n1. An admin or owner adds the attacker to a project with the built-in `manager` role; the attacker confirms the baseline, where owner-only endpoints are denied.\n\n```\nGET  /api/project/42/role     Cookie: semaphore=<manager-session>\n  -> {\"role\":\"manager\",\"permissions\":5}\nPUT  /api/project/42          Cookie: semaphore=<manager-session>\n  -> HTTP/1.1 403 Forbidden\n```\n\n2. The manager creates a custom role whose slug collides with the built-in `manager` and carries every permission bit.\n\n```\nPOST /api/project/42/roles    Cookie: semaphore=<manager-session>\nContent-Type: application/json\n{\"slug\":\"manager\",\"name\":\"pwn\",\"permissions\":15}\n  -> HTTP/1.1 201 Created\n     {\"slug\":\"manager\",\"name\":\"pwn\",\"permissions\":15,\"project_id\":42}\n```\n\n3. On the next request the manager holds the owner bitmask and performs owner-only actions.\n\n```\nGET  /api/project/42/role  -> {\"role\":\"manager\",\"permissions\":15}\nPUT  /api/project/42       {\"id\":42,\"name\":\"owned\",\"alert\":false}      -> 204 No Content\nPOST /api/project/42/users {\"user_id\":99,\"role\":\"task_runner\"}         -> 204 No Content\n```\n\nLive-verified: a manager with permissions `5` obtains permissions `15` with one POST, then changes project settings and adds project members, both of which return 403 before the role is created.\n\n## Impact\n\n- Full administrative control of the project from a non-owner role: change project settings, delete the project.\n- Add, remove, and re-role project members, including granting roles the attacker should not control.\n- Removal or demotion of the legitimate project owner.\n- Reached by the project `manager` role in default config with one request; not reachable by `task_runner`, `guest`, or unauthenticated callers.\n\n## Credit\n\nJan Kahmen, [turingpoint](https://www.turingpoint.de) (jan@turingpoint.de)","state":0,"publishedAt":"2026-09-03T19:23:42+00:00","modifiedAt":"2026-09-10T15:25:39.7664694+00:00","affected":[{"ecosystem":"Go","name":"github.com/semaphoreui/semaphore","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"0.0.0-20260705182501-bb2a4e1f08c8"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/semaphoreui/semaphore/security/advisories/GHSA-cxvf-gvfq-36w2","https://nvd.nist.gov/vuln/detail/CVE-2026-73293","https://github.com/semaphoreui/semaphore/commit/1c4bb65df114962134f8829d4a03667106a01a68","https://github.com/semaphoreui/semaphore/commit/bb2a4e1f08c8023e618f8dd6eaca73554f2c33bb","https://github.com/semaphoreui/semaphore","https://github.com/semaphoreui/semaphore/releases/tag/v2.18.19","https://github.com/semaphoreui/semaphore/releases/tag/v2.19.5-beta5"],"sourceUrl":"https://github.com/advisories/GHSA-cxvf-gvfq-36w2","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-cxvf-gvfq-36w2","identifiers":["GHSA-cxvf-gvfq-36w2","CVE-2026-73293","GO-2026-6371"]},"retained":false,"historicalAffected":[]},{"revision":"315941c9181742ceb70386a63996a073","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-6371","aliases":["CVE-2026-73293","GHSA-cxvf-gvfq-36w2"],"title":"Semaphore UI: Manager-to-owner privilege escalation via custom-role slug collision in github.com/semaphoreui/semaphore","description":"Semaphore UI: Manager-to-owner privilege escalation via custom-role slug collision in github.com/semaphoreui/semaphore","state":0,"publishedAt":"2026-09-10T14:48:42+00:00","modifiedAt":"2026-09-10T15:15:13.5609593+00:00","affected":[{"ecosystem":"Go","name":"github.com/semaphoreui/semaphore","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"0.0.0-20260705182501-bb2a4e1f08c8"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/semaphoreui/semaphore/security/advisories/GHSA-cxvf-gvfq-36w2","https://nvd.nist.gov/vuln/detail/CVE-2026-73293","https://github.com/semaphoreui/semaphore/commit/1c4bb65df114962134f8829d4a03667106a01a68","https://github.com/semaphoreui/semaphore/commit/bb2a4e1f08c8023e618f8dd6eaca73554f2c33bb","https://github.com/semaphoreui/semaphore/releases/tag/v2.18.19","https://github.com/semaphoreui/semaphore/releases/tag/v2.19.5-beta5"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-6371","license":"OSV · upstream source license applies","key":"osv:GO-2026-6371","identifiers":["GO-2026-6371","CVE-2026-73293","GHSA-cxvf-gvfq-36w2"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-25T22:04:08.5875992+00:00","complete":true,"records":1756,"lastAttemptAt":"2026-10-25T22:04:08.5875992+00:00","lastSuccessAt":"2026-10-25T22:04:08.8596165+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:04:08.8596241+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-1a687ad2a0b90150aa7d97c9f39e63de695ae2db23e31ebc28df1492c461b23c-1c072e7db56f0d3179c99f5b33ed9988c328ad75783993f151d8522bc700aaba","complete":true,"records":414046,"lastAttemptAt":"2026-10-25T22:02:18.7733512+00:00","lastSuccessAt":"2026-10-25T22:02:18.6654575+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:02:18.7733512+00:00","snapshotPublishedAt":"2026-10-25T21:21:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-25T22:04:11.413428+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":4764,"expectedIdentifiers":13474},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-25T22:04:08.5875992+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-25T22:04:08.5875992+00:00","lastSuccessAt":"2026-10-25T22:04:08.8610999+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:04:08.8611051+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-204a3fb93a00487e8f7f36db01dc851d","complete":true,"records":13413,"lastAttemptAt":"2026-10-25T22:04:09.4303098+00:00","lastSuccessAt":"2026-10-25T16:19:28.681+00:00","error":null,"lastVerifiedAt":"2026-10-25T16:19:28.681+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13474,"expectedIdentifiers":13474},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-2375a4e597279abf92e8747e140fe8da9d421877cd49cae3ac69a2cb78469b2c","complete":true,"records":9779,"lastAttemptAt":"2026-10-25T22:04:08.4463409+00:00","lastSuccessAt":"2026-10-24T13:19:53.1346702+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:04:08.4463409+00:00","snapshotPublishedAt":"2026-10-24T03:03:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-16ad89dfea13ab9e9b0108e63a759d63bd4559cc68b58491107d62ee35bbbaf2","complete":true,"records":1965,"lastAttemptAt":"2026-10-25T22:02:18.9302775+00:00","lastSuccessAt":"2026-10-23T16:01:26.4487605+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:02:18.9302775+00:00","snapshotPublishedAt":"2026-10-21T12:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-7da67a15aa6e56a0e3081a7646dc74d537e6ef974afc593c2b1794ed01970648","complete":true,"records":2969,"lastAttemptAt":"2026-10-25T22:04:08.554556+00:00","lastSuccessAt":"2026-10-24T13:19:59.1145547+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:04:08.554556+00:00","snapshotPublishedAt":"2026-10-24T08:47:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-11236ada05a0588e51df37636716526867f73fb127392c49680b6f8561496a99","complete":true,"records":230781,"lastAttemptAt":"2026-10-25T22:04:08.3201814+00:00","lastSuccessAt":"2026-10-25T22:04:07.173333+00:00","error":null,"lastVerifiedAt":"2026-10-25T22:04:08.3201814+00:00","snapshotPublishedAt":"2026-10-25T21:33:06+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}