Date: 2026-06-20. Source: gitea-src @ origin/main 645b100 (2026-06-19, fetched fresh). Daily advisory watch surfaced 3 NEW Gitea High advisories dated 2026-06-14 (after the 06-13 watch):
- GHSA-wrr5-99h5-gq57 - Public-only tokens bypass private-resource restrictions on /api/v1/user (High)
- GHSA-fhx7-m96w-mv29 - API Fork Missing CanCreateOrgRepo Check (High)
- GHSA-9cpj-qc93-vw8v - Stored XSS via glTF in Gitea 3D File Viewer (High)
Both backend-confirmable authz advisories deep-probed for incomplete-fix siblings (our cycle239-feed edge). Both WALK CLEAN.
Fix: checkTokenPublicOnly() middleware added to the /user self-group (routers/api/v1/api.go:1103-1221). Mechanism: the middleware only enforces when ctx.PublicOnly AND ctx.Data["requiredScopeCategories"] (set by tokenRequiresScopes) is non-empty AND the category switch handles that resource type - a 3-leg dependency, classic per-handler-scattered signal.
Set-difference (endpoints declaring tokenRequiresScopes but lacking BOTH checkTokenPublicOnly and rejectPublicOnly) produced 17 raw candidates, but the 2 strongest non-self ones enforce PublicOnly INTERNALLY:
- org.GetAll (GET /orgs, the prior session's open lead) - calls searchOpts.ApplyPublicOnly(ctx.PublicOnly) + visibility Private gated to Doer.IsAdmin. The missing middleware is redundant. Prior /orgs lead REFUTED.
- repo.GetByID (GET /repositories/{id}, raw-ID fetch) - enforces ctx.TokenCanAccessRepo(repo) (same helper the middleware's Repository-case uses) + GetDoerRepoPermission + HasAnyUnitAccess. Public-only token on a private repo -> 404.
Key insight (banked): Gitea enforces public-only via TWO interchangeable mechanisms - the checkTokenPublicOnly middleware OR internal helpers (ApplyPublicOnly, TokenCanAccessRepo). A middleware-only set-difference is dominated by FALSE POSITIVES because the handler layer also enforces. Must verify the handler body before claiming a missing-middleware bypass. Enforcement is CONSISTENT (just dual-mechanism) -> per the META heuristic (edge pays only on INCONSISTENT cross-sibling fixes), walk.
Fix: CreateFork now routes org-target forks through the shared helper prepareDoerCreateRepoInOrg (routers/api/v1/repo/fork.go:88), which enforces HasOrgOrUserVisible + (!Doer.IsAdmin -> org.CanCreateOrgRepo).
Census of ALL org-targeting repo-creation endpoints + their org-creation gate:
- CreateOrgRepo (POST /orgs/{org}/repos) - via shared helper (repo.go:490). OK.
- CreateFork (POST /repos/{owner}/{repo}/forks) - via shared helper (fork.go:154) = the fix. OK.
- Generate (POST /repos/{template}/generate) - inline OrgFromUser(ctxUser).CanCreateOrgRepo (repo.go:399). OK.
- Migrate (POST /repos/migrate) - uses organization.OrgFromUser(repoOwner).IsOwnedBy(ctx, Doer.ID) (migrate.go) - the classic "missed sibling" suspect, but IsOwnedBy is STRICTER than CanCreateOrgRepo (owners are a subset of can-create). Asymmetry is in the SAFE/more-restrictive direction = not a vuln.
Every org-creation path enforces an org-creation permission; fork was the lone gap, now closed via the shared helper. The one asymmetry (Migrate=IsOwnedBy) over-restricts, not under-restricts. WALK CLEAN.
Frontend/render bug; not curl-confirmable on a no-headless-browser box (per the Grafana cycle239c lesson). Flagged as a browser-class lead for a Playwright-capable box; not pursued here.
Watch did its job: detected 3 fresh advisories, deep-probed the 2 backend-authz ones = both WALK CLEAN. Reconfirms the session META: Gitea is well-maintained and fixes CONSISTENTLY (the cycle239 feed token-scope bug was the genuine per-handler OUTLIER; subsequent advisory fixes are consistent across siblings). Refined the set-difference primitive: when a project has a DUAL enforcement model (middleware OR internal helper), middleware-only set-difference is necessary-not-sufficient - verify the handler body before claiming a bypass. (Companion to the GitLab CVE-2026-6552 write-site-census refinement banked the same day.)