Summary
The web attachment handler contains a guard that rejects a request for an attachment made through a repository other than the one that owns it. That guard is applied only to attachments created after 16 January 2026; older attachments skip it even when their owning-repository id is correctly populated. When the guard is skipped, the handler evaluates permission against the repository named in the request URL instead of the repository that owns the attachment. An attachment belonging to a private repository can therefore be retrieved by requesting it through any public repository's attachment path. The route allows anonymous access, so no authentication is required.
Details
In routers/web/repo/attachment.go the cross-repository check is gated only on the attachment's creation timestamp, unlike its two sibling call sites which also require the owning-repository id to be unset. A migration backfills that id on upgrade, so the timestamp-only exemption protects no legitimate rows and instead allows permission to be checked against the wrong repository. Downstream draft-release and token-scope checks inherit the same wrong subject. Attachment UUIDs are random and not enumerable, so exploitation requires knowledge of a specific attachment UUID (for example from a removed collaborator, a public-to-private conversion, notification mail, webhook payloads, or proxy/CDN logs).
Impact
Disclosure of private-repository attachment contents — issue and pull request attachments and release assets — to an unauthenticated caller who knows the attachment UUID. Incorrect authorization / cross-repository access control bypass. Affects any instance that held attachments created before 16 January 2026.
Affected versions
Gitea >= 1.26.0, <= 1.27.2.
Patches
Fixed in Gitea 1.27.3 (#39048, #39077).
Workarounds
None. Upgrade to 1.27.3.
Summary
The web attachment handler contains a guard that rejects a request for an attachment made through a repository other than the one that owns it. That guard is applied only to attachments created after 16 January 2026; older attachments skip it even when their owning-repository id is correctly populated. When the guard is skipped, the handler evaluates permission against the repository named in the request URL instead of the repository that owns the attachment. An attachment belonging to a private repository can therefore be retrieved by requesting it through any public repository's attachment path. The route allows anonymous access, so no authentication is required.
Details
In
routers/web/repo/attachment.gothe cross-repository check is gated only on the attachment's creation timestamp, unlike its two sibling call sites which also require the owning-repository id to be unset. A migration backfills that id on upgrade, so the timestamp-only exemption protects no legitimate rows and instead allows permission to be checked against the wrong repository. Downstream draft-release and token-scope checks inherit the same wrong subject. Attachment UUIDs are random and not enumerable, so exploitation requires knowledge of a specific attachment UUID (for example from a removed collaborator, a public-to-private conversion, notification mail, webhook payloads, or proxy/CDN logs).Impact
Disclosure of private-repository attachment contents — issue and pull request attachments and release assets — to an unauthenticated caller who knows the attachment UUID. Incorrect authorization / cross-repository access control bypass. Affects any instance that held attachments created before 16 January 2026.
Affected versions
Gitea
>= 1.26.0, <= 1.27.2.Patches
Fixed in Gitea 1.27.3 (#39048, #39077).
Workarounds
None. Upgrade to 1.27.3.