GHSA-4565-R4X7-HG8J
Vulnerability from github – Published: 2026-06-23 16:52 – Updated: 2026-06-23 16:52Summary
A repository admin collaborator can escalate their privileges to owner-level access by exploiting an off-by-one error in the ChangeCollaborationAccessMode function.
Vulnerable Code
In internal/database/repo_collaboration.go, line 129:
func (r *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessMode) error {
// Discard invalid input
if mode <= AccessModeNone || mode > AccessModeOwner {
return nil
}
AccessModeOwner has value 4. The check mode > AccessModeOwner evaluates to 4 > 4 = false, allowing AccessModeOwner to pass through. The correct check should be mode >= AccessModeOwner.
The web route at internal/route/repo/setting.go:413-416 takes the mode as a raw integer from query parameters:
func ChangeCollaborationAccessMode(c *context.Context) {
if err := c.Repo.Repository.ChangeCollaborationAccessMode(
c.QueryInt64("uid"),
database.AccessMode(c.QueryInt("mode"))); err != nil {
This allows an admin collaborator to POST mode=4 and escalate to owner.
Impact
A repository admin collaborator (AccessModeAdmin = 3) can escalate to owner-level access (AccessModeOwner = 4), gaining the ability to: - Delete the repository - Transfer repository ownership to another user - Erase wiki data - Perform all other owner-only operations
The access table is also updated (line 181), so the escalated permissions persist across sessions.
Contrast
The API route at internal/route/api/v1/repo_collaborators.go:46 uses ParseAccessMode() which only returns Read, Write, or Admin - never Owner. The API endpoint is not affected.
Steps to Reproduce
- User A creates a private repository
- User A adds User B as a collaborator with Admin access (mode=3)
- User B logs in and navigates to the repository settings collaboration page
- User B sends a POST request:
POST /{owner}/{repo}/settings/collaboration/access_mode?uid={B_uid}&mode=4 - User B now has Owner access - the "Danger Zone" section appears with "Delete This Repository" and "Transfer Ownership" buttons
Suggested Fix
Change the validation in internal/database/repo_collaboration.go line 129 from:
if mode <= AccessModeNone || mode > AccessModeOwner {
to:
if mode <= AccessModeNone || mode >= AccessModeOwner {
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "gogs.io/gogs"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.14.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-52804"
],
"database_specific": {
"cwe_ids": [
"CWE-193"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T16:52:30Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nA repository admin collaborator can escalate their privileges to owner-level access by exploiting an off-by-one error in the `ChangeCollaborationAccessMode` function.\n\n## Vulnerable Code\n\nIn `internal/database/repo_collaboration.go`, line 129:\n\n```go\nfunc (r *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessMode) error {\n // Discard invalid input\n if mode \u003c= AccessModeNone || mode \u003e AccessModeOwner {\n return nil\n }\n```\n\n`AccessModeOwner` has value 4. The check `mode \u003e AccessModeOwner` evaluates to `4 \u003e 4 = false`, allowing `AccessModeOwner` to pass through. The correct check should be `mode \u003e= AccessModeOwner`.\n\nThe web route at `internal/route/repo/setting.go:413-416` takes the mode as a raw integer from query parameters:\n\n```go\nfunc ChangeCollaborationAccessMode(c *context.Context) {\n if err := c.Repo.Repository.ChangeCollaborationAccessMode(\n c.QueryInt64(\"uid\"),\n database.AccessMode(c.QueryInt(\"mode\"))); err != nil {\n```\n\nThis allows an admin collaborator to POST `mode=4` and escalate to owner.\n\n## Impact\n\nA repository admin collaborator (AccessModeAdmin = 3) can escalate to owner-level access (AccessModeOwner = 4), gaining the ability to:\n- **Delete the repository**\n- **Transfer repository ownership** to another user\n- **Erase wiki data**\n- Perform all other owner-only operations\n\nThe `access` table is also updated (line 181), so the escalated permissions persist across sessions.\n\n## Contrast\n\nThe API route at `internal/route/api/v1/repo_collaborators.go:46` uses `ParseAccessMode()` which only returns Read, Write, or Admin - never Owner. The API endpoint is not affected.\n\n## Steps to Reproduce\n\n1. User A creates a private repository\n2. User A adds User B as a collaborator with **Admin** access (mode=3)\n3. User B logs in and navigates to the repository settings collaboration page\n4. User B sends a POST request:\n ```\n POST /{owner}/{repo}/settings/collaboration/access_mode?uid={B_uid}\u0026mode=4\n ```\n5. User B now has **Owner** access - the \"Danger Zone\" section appears with \"Delete This Repository\" and \"Transfer Ownership\" buttons\n\n## Suggested Fix\n\nChange the validation in `internal/database/repo_collaboration.go` line 129 from:\n```go\nif mode \u003c= AccessModeNone || mode \u003e AccessModeOwner {\n```\nto:\n```go\nif mode \u003c= AccessModeNone || mode \u003e= AccessModeOwner {\n```",
"id": "GHSA-4565-r4x7-hg8j",
"modified": "2026-06-23T16:52:30Z",
"published": "2026-06-23T16:52:30Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gogs/gogs/security/advisories/GHSA-4565-r4x7-hg8j"
},
{
"type": "WEB",
"url": "https://github.com/gogs/gogs/pull/8227"
},
{
"type": "WEB",
"url": "https://github.com/gogs/gogs/commit/1fdc9cc28e159135cfa4d6b11ecd5daa0f8ce22b"
},
{
"type": "PACKAGE",
"url": "https://github.com/gogs/gogs"
},
{
"type": "WEB",
"url": "https://github.com/gogs/gogs/releases/tag/v0.14.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:P",
"type": "CVSS_V4"
}
],
"summary": "Gogs Vulnerable to Privilege Escalation via Collaboration Access Mode Validation"
}
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.