Monitor vulnerabilities like this one.
Sign up free to get alerted when software you use is affected.
5.3
Gogs Allows Unwanted Label Changes Across Repositories
CVE-2026-25229
GHSA-cv22-72px-f4gh
Summary
Gogs has a security problem that allows users with write access to any repository to modify labels in other repositories. This can lead to unauthorized changes to labels in sensitive repositories. To fix this, Gogs developers will need to update the code to correctly check that the label being modified belongs to the repository specified in the URL path.
What to do
- Update gogs.io gogs to version 0.14.0.
Affected software
| Vendor | Product | Affected versions | Fix available |
|---|---|---|---|
| gogs.io | gogs | <= 0.13.4 | 0.14.0 |
| gogs | gogs | <= 0.14.1 | – |
Original title
Gogs has an Authorization Bypass Allows Cross-Repository Label Modification in Gogs
Original description
### **Summary**
A broken access control vulnerability in Gogs allows authenticated users with write access to any repository to modify labels belonging to other repositories. The `UpdateLabel` function in the Web UI (`internal/route/repo/issue.go`) fails to verify that the label being modified belongs to the repository specified in the URL path, enabling cross-repository label tampering attacks.
### **Details**
The vulnerability exists in the Web UI's label update endpoint `POST /:username/:reponame/labels/edit`. The handler function `UpdateLabel` uses an incorrect database query function that bypasses repository ownership validation:
**Vulnerable Code** (`internal/route/repo/issue.go:1040-1054`):
```plain
func UpdateLabel(c *context.Context, f form.CreateLabel) {
l, err := database.GetLabelByID(f.ID) // ❌ No repository validation
if err != nil {
c.NotFoundOrError(err, "get label by ID")
return
}
// ❌ Missing validation: l.RepoID != c.Repo.Repository.ID
l.Name = f.Title
l.Color = f.Color
if err := database.UpdateLabel(l); err != nil {
c.Error(err, "update label")
return
}
c.RawRedirect(c.Repo.MakeURL("labels"))
}
```
**Root Cause**:
1. The function calls `database.GetLabelByID(f.ID)` which internally passes `repoID=0` to the ORM layer
2. According to code comments in `internal/database/issue_label.go:147-166`, passing `repoID=0` causes the ORM to ignore repository restrictions
3. No validation checks whether `l.RepoID == c.Repo.Repository.ID` before updating
4. The middleware `reqRepoWriter()` only validates write access to the repository in the URL path, not the label's actual repository
**Inconsistency with Other Functions**:
+ `NewLabel`: Correctly sets `RepoID = c.Repo.Repository.ID`
+ `DeleteLabel`: Correctly uses `database.DeleteLabel(c.Repo.Repository.ID, id)`
+ API `EditLabel`: Correctly uses `database.GetLabelOfRepoByID(c.Repo.Repository.ID, id)`
- ****Only `UpdateLabel` in ****Web UI**** uses the vulnerable pattern****
### **PoC**
**Prerequisites**:
+ Two user accounts: Alice (attacker) and Bob (victim)
+ alice has written access to repo-a
+ Bob owns repo-b with labels
**Step 1: Identify Target Label ID**
1. Login as bob, navigate to bob/repo-b/labels
2. Open browser DevTools (F12) → Network tab
3. Click edit on any label
4. Observe the form data: id=<LABEL_ID>
5. Example: id=1
**Step 2: Execute Attack**
```plain
# Login as alice, get session cookie
# Open DevTools → Application → Cookies → i_like_gogs
# Copy the cookie value
# Send malicious request
curl -X POST "http://localhost:3000/alice/repo-a/labels/edit" \
-H "Cookie: i_like_gogs=<ALICE_SESSION_COOKIE>" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "id=1&title=HACKED-BY-ALICE&color=%23000000"
# Expected response: 302 Found (redirect)
```
**Step 3: Verify Impact**
1. Login as bob
2. Navigate to bob/repo-b/labels
3. Observe: Label "P0-Critical" is now "HACKED-BY-ALICE" with black color
### **Impact**
1. **Issue Classification Disruption**: Modify critical labels (e.g., "P0-Critical" → "P3-Low") causing urgent issues to be deprioritized
2. **Security Issue Concealment**: Change "security" labels to "documentation" to hide vulnerability reports from security teams
3. **Workflow**** Sabotage**: Alter labels used in CI/CD automation, breaking deployment pipelines
4. **Mass Disruption**: Batch modifies all labels across multiple repositories using ID enumeration
**Recommended Fix**:
```plain
func UpdateLabel(c *context.Context, f form.CreateLabel) {
l, err := database.GetLabelOfRepoByID(c.Repo.Repository.ID, f.ID)
if err != nil {
c.NotFoundOrError(err, "get label of repository by ID")
return
}
// Now label ownership is validated at database layer
l.Name = f.Title
l.Color = f.Color
if err := database.UpdateLabel(l); err != nil {
c.Error(err, "update label")
return
}
c.RawRedirect(c.Repo.MakeURL("labels"))
}
```
A broken access control vulnerability in Gogs allows authenticated users with write access to any repository to modify labels belonging to other repositories. The `UpdateLabel` function in the Web UI (`internal/route/repo/issue.go`) fails to verify that the label being modified belongs to the repository specified in the URL path, enabling cross-repository label tampering attacks.
### **Details**
The vulnerability exists in the Web UI's label update endpoint `POST /:username/:reponame/labels/edit`. The handler function `UpdateLabel` uses an incorrect database query function that bypasses repository ownership validation:
**Vulnerable Code** (`internal/route/repo/issue.go:1040-1054`):
```plain
func UpdateLabel(c *context.Context, f form.CreateLabel) {
l, err := database.GetLabelByID(f.ID) // ❌ No repository validation
if err != nil {
c.NotFoundOrError(err, "get label by ID")
return
}
// ❌ Missing validation: l.RepoID != c.Repo.Repository.ID
l.Name = f.Title
l.Color = f.Color
if err := database.UpdateLabel(l); err != nil {
c.Error(err, "update label")
return
}
c.RawRedirect(c.Repo.MakeURL("labels"))
}
```
**Root Cause**:
1. The function calls `database.GetLabelByID(f.ID)` which internally passes `repoID=0` to the ORM layer
2. According to code comments in `internal/database/issue_label.go:147-166`, passing `repoID=0` causes the ORM to ignore repository restrictions
3. No validation checks whether `l.RepoID == c.Repo.Repository.ID` before updating
4. The middleware `reqRepoWriter()` only validates write access to the repository in the URL path, not the label's actual repository
**Inconsistency with Other Functions**:
+ `NewLabel`: Correctly sets `RepoID = c.Repo.Repository.ID`
+ `DeleteLabel`: Correctly uses `database.DeleteLabel(c.Repo.Repository.ID, id)`
+ API `EditLabel`: Correctly uses `database.GetLabelOfRepoByID(c.Repo.Repository.ID, id)`
- ****Only `UpdateLabel` in ****Web UI**** uses the vulnerable pattern****
### **PoC**
**Prerequisites**:
+ Two user accounts: Alice (attacker) and Bob (victim)
+ alice has written access to repo-a
+ Bob owns repo-b with labels
**Step 1: Identify Target Label ID**
1. Login as bob, navigate to bob/repo-b/labels
2. Open browser DevTools (F12) → Network tab
3. Click edit on any label
4. Observe the form data: id=<LABEL_ID>
5. Example: id=1
**Step 2: Execute Attack**
```plain
# Login as alice, get session cookie
# Open DevTools → Application → Cookies → i_like_gogs
# Copy the cookie value
# Send malicious request
curl -X POST "http://localhost:3000/alice/repo-a/labels/edit" \
-H "Cookie: i_like_gogs=<ALICE_SESSION_COOKIE>" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "id=1&title=HACKED-BY-ALICE&color=%23000000"
# Expected response: 302 Found (redirect)
```
**Step 3: Verify Impact**
1. Login as bob
2. Navigate to bob/repo-b/labels
3. Observe: Label "P0-Critical" is now "HACKED-BY-ALICE" with black color
### **Impact**
1. **Issue Classification Disruption**: Modify critical labels (e.g., "P0-Critical" → "P3-Low") causing urgent issues to be deprioritized
2. **Security Issue Concealment**: Change "security" labels to "documentation" to hide vulnerability reports from security teams
3. **Workflow**** Sabotage**: Alter labels used in CI/CD automation, breaking deployment pipelines
4. **Mass Disruption**: Batch modifies all labels across multiple repositories using ID enumeration
**Recommended Fix**:
```plain
func UpdateLabel(c *context.Context, f form.CreateLabel) {
l, err := database.GetLabelOfRepoByID(c.Repo.Repository.ID, f.ID)
if err != nil {
c.NotFoundOrError(err, "get label of repository by ID")
return
}
// Now label ownership is validated at database layer
l.Name = f.Title
l.Color = f.Color
if err := database.UpdateLabel(l); err != nil {
c.Error(err, "update label")
return
}
c.RawRedirect(c.Repo.MakeURL("labels"))
}
```
nvd CVSS3.1
6.5
nvd CVSS4.0
5.3
Vulnerability type
CWE-284
Improper Access Control
Published: 17 Feb 2026 · Updated: 11 Mar 2026 · First seen: 6 Mar 2026