# Gitea: Git LFS object reuse allows non-Code access to authorize private source objects

Gitea's LFS object reuse check used broad repo accessibility (unit.TypeInvalid), letting a user with only Issues access to a private repo associate and download its LFS objects.

- Payout: Research
- Severity: high
- Program: Gitea
- Found by (vendor credit): m2hcz
- Found by: m2hcz
- Disclosed: 2026-07-21
- CVE: CVE-2026-28740
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-2m9v-5q2g-58vq
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-2m9v-5q2g-58vq
- Tags: area:web domain:web impact:data-leak kind:research platform:ghsa sev:high tech:go technique:source-review vuln:access-control vuln:idor vuln:info-disclosure

**Target:** Git LFS BatchHandler/UploadHandler endpoints (services/lfs/server.go)
**Root cause:** LFSObjectAccessible calls repo_model.AccessibleRepositoryCondition with unit.TypeInvalid, which grants access via broad repo/team membership (team_repo, team_user) without validating Code-unit access (team_unit) to the source repository owning the LFS object.
**Steps:**
1. Attacker has Code write to target repo and only Issues access (via org team) to a private source repo.
2. Attacker learns an existing LFS object OID and size from the private source repo.
3. Call the LFS batch/upload path so `git_model.LFSObjectAccessible(ctx, ctx.Doer, p.Oid)` is evaluated for the source OID.
4. Because unit.TypeInvalid is used, the accessibility condition matches team membership and returns true.
5. `NewLFSMetaObject(ctx, targetRepo.ID, pointer)` creates LFS metadata in the attacker's target repo, associating the foreign object.
6. Download the object through the target repo to disclose private source content.
**How found:** Code review of the LFS upload/reuse path: noticed LFSObjectAccessible passes unit.TypeInvalid to AccessibleRepositoryCondition, and compared it against Code-specific checks that use a concrete unit type and include team_unit validation.
**Exploitation:** Authenticated user with Code write on a target repo and Issues-only access to a private source repo submits the source object's OID/size to the LFS batch/upload endpoints; the permissive accessibility check passes, metadata is created in the target repo, and the object becomes downloadable there, disclosing private LFS content.
**Insight:** When an authorization helper takes a unit type, grep for callers passing a sentinel/invalid unit — those paths silently fall back to broad repo/team membership and skip per-unit (e.g. Code) checks; LFS object reuse is a good place to test cross-repo OID association.

