Ce mail provient de l'extérieur, restons vigilants ===================================================================== CERT-Renater Note d'Information No. 2026/VULN602 _____________________________________________________________________ DATE : 08/06/2026 HARDWARE PLATFORM(S): / OPERATING SYSTEM(S): Systems running gitea (Go) versions prior to 1.26.2. ===================================================================== https://github.com/go-gitea/gitea/security/advisories/GHSA-mm7c-rhg6-qr4r https://github.com/go-gitea/gitea/security/advisories/GHSA-9r5x-wg6m-x2rc https://github.com/go-gitea/gitea/security/advisories/GHSA-8qw8-rq86-9pc2 https://github.com/go-gitea/gitea/security/advisories/GHSA-cc8w-r4qh-3v65 https://github.com/go-gitea/gitea/security/advisories/GHSA-cr4g-f395-h25h https://github.com/go-gitea/gitea/security/advisories/GHSA-3fwp-p5rj-2pxf _____________________________________________________________________ Authorization Bypass via "Allow edits from maintainers" allows unauthorized commits to any readable repo High lunny published GHSA-mm7c-rhg6-qr4r Jun 6, 2026 Package code.gitea.io/gitea (Go) Affected versions <=1.26.1 Patched versions 1.26.2 Description Summary Any authenticated low-privilege user with read access to a repository can push arbitrary commits directly to that repository, bypassing all write-access checks. Vulnerability Gitea's "Allow edits from maintainers" PR option can be abused via reverse-fork PRs: The web UI PR-create endpoint binds allow_maintainer_edit=true without verifying that the submitter has write access to the HEAD repository. Gitea allows creating a PR where BASE = attacker's fork and HEAD = upstream target. The attacker is "maintainer" of the BASE (their own fork), so the flag is set against the upstream HEAD. On git push over HTTP/SSH, Gitea relaxes the required access mode to Read when SupportProcReceive is enabled (routers/web/repo/githttp.go, routers/private/serv.go) and defers enforcement to the pre-receive hook. The pre-receive hook calls CanMaintainerWriteToBranch (models/issues/pull_list.go), which finds the malicious PR, sees AllowMaintainerEdit=true, and checks whether the pusher has write access to the BASE repo. Since BASE is the attacker's own fork, the check passes and the push is authorized against the upstream. Exploitation Attacker forks the target repository. Attacker visits the web compare endpoint and creates a PR with BASE = their_fork, HEAD = upstream, and "Allow edits from maintainers" checked. Attacker clones their fork, makes a commit, and runs git push — the push is accepted. Reproduction python3 poc.py --repo http://gitea:3000/victim/repo --user attacker --password attacker_pass poc.py Expected output: [+] target: victim/my_repo default branch: main [*] forking -> attacker/my_repo_pocfork (202) [+] fork ready [+] malicious PR created (BASE=attacker fork, HEAD=upstream) remote: . Processing 1 references remote: Processed 1 references in total To http://192.168.101.20:3000/victim/my_repo.git e5c07b3..9a0b884 main -> main [+] latest commit on victim/my_repo@main: 'PoC: unauthorized commit via maintainer-edit bypass' [+] CONFIRMED: unauthorized push to upstream succeeded. A PWNED.txt file will appear on the target repo's default branch, committed by the attacker who has no write access. Impact Full repository compromise. Any logged-in user can backdoor any repository they can read, including all public repositories on the instance. Suggested Fix Two independent checks are missing; both should be added for defense in depth: At PR creation: before setting AllowMaintainerEdit = true, verify the submitter has write access to the HEAD repository. In CanMaintainerWriteToBranch: verify that the PR's HEAD repo matches the repository being pushed to, and that the PR was opened by a legitimate owner/writer of the HEAD repository. Do not trust AllowMaintainerEdit solely based on BASE write access. Severity High 8.5/ 10 CVSS v3 base metrics Attack vector Network Attack complexity Low Privileges required Low User interaction None Scope Changed Confidentiality Low Integrity High Availability None CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:N CVE ID CVE-2026-26231 Weaknesses Weakness CWE-863 Credits @ddd ddd Reporter _____________________________________________________________________ OAuth2 access token scope enforcement bypass via HTTP Basic authentication High lunny published GHSA-9r5x-wg6m-x2rc Jun 6, 2026 Package code.gitea.io/gitea (Go) Affected versions <= 1.26.1 Patched versions 1.26.2 Description Summary Gitea fails to enforce OAuth2 access token scopes when the token is submitted via HTTP Basic authentication instead of a Bearer token. An OAuth2 application granted only read:user can use the same token as Authorization: Basic base64(:x-oauth-basic) and perform write actions, including modifying profiles, adding email addresses, creating repositories, and deleting repositories as the authorizing user. Details Root cause: services/auth/basic.go accepts OAuth2 access tokens through the Basic auth path but does not store the token scope in the request context: // services/auth/basic.go if uid != 0 { store.GetData()["LoginMethod"] = OAuth2TokenMethodName store.GetData()["IsApiToken"] = true // scope is NOT set return u, nil } The scope enforcement middleware in routers/api/v1/api.go exits early when ApiTokenScope is absent: // routers/api/v1/api.go — tokenRequiresScopes scope, scopeExists := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) if ctx.Data["IsApiToken"] != true || !scopeExists { return //<- exits without checking scope, all actions permitted } When a token arrives via Bearer, ApiTokenScope is populated and scope checks apply normally. When the same token arrives via Basic auth, ApiTokenScope is never set, so tokenRequiresScopes returns immediately and no scope is enforced. Suggested fix: When an OAuth2 access token is accepted in services/auth/basic.go, populate ApiTokenScope in the request context identically to the Bearer-token OAuth2 path. PoC Create an OAuth2 application in Gitea. Authorize it as a normal user with scope read:user only. Take the resulting access token and call a write endpoint both ways: Bearer | correctly blocked: Authorization: Bearer PATCH /api/v1/user/settings -> 403 Forbidden Basic | bypass: Authorization: Basic base64(:x-oauth-basic) PATCH /api/v1/user/settings -> 200 OK All verified bypass endpoints using a read:user-only token: Endpoint Bearer Basic PATCH /api/v1/user/settings 403 200 POST /api/v1/user/emails 403 200 POST /api/v1/user/repos 403 200 PATCH /api/v1/repos/{owner}/{repo} 403 200 DELETE /api/v1/repos/{owner}/{repo} 403 200 The bypass respects the user's normal repository permissions, it does not grant access to repositories the user cannot otherwise reach, and does not escalate to admin. Impact Any OAuth2 application with any restricted scope can silently operate beyond its granted permissions by switching from Bearer to Basic auth. An attacker who obtains a token (e.g. via a malicious OAuth2 app a user authorized) can: Modify the victim's profile and settings Add attacker-controlled email addresses to the victim's account Create repositories as the victim Modify or delete the victim's private repositories The entire OAuth2 scope system is effectively bypassed for any token submitted via Basic auth. Severity High 8.1/ 10 CVSS v3 base metrics Attack vector Network Attack complexity Low Privileges required Low User interaction None Scope Unchanged Confidentiality High Integrity High Availability None CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N CVE ID CVE-2026-28699 Weaknesses Weakness CWE-284 Weakness CWE-863 Credits @Alardiians Alardiians Reporter _____________________________________________________________________ Critical Vulnerability - Already emailed High lunny published GHSA-8qw8-rq86-9pc2 Jun 6, 2026 Package code.gitea.io/gitea (Go) Affected versions <= 1.26.1 Patched versions 1.26.2 Description Summary Hi team, We believe we've identified a critical vulnerability in Gitea. We've already reported it via the email listed on your site (security@gitea.io) from (dev@noscope.com), and submitted an encrypted report. Please let us know if you've received it, and whether you'd prefer us to also report it here. Looking forward to hearing from you. Severity High 8.2/ 10 CVSS v3 base metrics Attack vector Network Attack complexity Low Privileges required None User interaction None Scope Unchanged Confidentiality High Integrity Low Availability None CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N CVE ID CVE-2026-27771 Weaknesses No CWEs Credits @DevNoScope DevNoScope Reporter _____________________________________________________________________ Git Smart HTTP Skips Repository Token Scopes for Bearer Tokens High lunny published GHSA-cc8w-r4qh-3v65 May 25, 2026 Package No package listed Affected versions <= 1.26.1 Patched versions 1.26.2 Description Summary Gitea v1.26.1 enforces repository-scoped access-token permissions on repository operations. In the Git Smart HTTP path, however, this check runs only when the token is presented via HTTP Basic authentication — CheckRepoScopedToken() returns early unless ctx.IsBasicAuth is true — so the same token sent as Authorization: Bearer bypasses the scope check entirely. As a result, a PAT or OAuth2 token presented as a Bearer credential can clone or fetch private repositories without the read:repository scope, and likewise reach the Git push without write:repository. Details Git Smart HTTP routes allow both Basic auth and OAuth2/Bearer auth: // routers/web/web.go addOwnerRepoGitHTTPRouters( m, repo.HTTPGitEnabledHandler, webAuth.AllowBasic, webAuth.AllowOAuth2, repo.CorsHandler(), optSignInFromAnyOrigin, context.UserAssignmentWeb(), ) The Git HTTP authorization path calls CheckRepoScopedToken() before falling through to normal repository RBAC: // routers/web/repo/githttp.go if askAuth { if !ctx.IsSigned { ctx.HTTPError(http.StatusUnauthorized) return nil } context.CheckRepoScopedToken(ctx, repo, auth_model.GetScopeLevelFromAccessMode(accessMode)) if ctx.Written() { return nil } // normal repository RBAC follows } However, CheckRepoScopedToken() only enforces token scopes for Basic-authenticated requests: // services/context/permission.go func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) { if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true { return } scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) if ok { requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository) // public-only and required repository scope checks follow } } The Bearer/OAuth2 auth path still records the token scope: // services/auth/oauth2.go accessTokenScope, uid := GetOAuthAccessTokenScopeAndUserID(ctx, tokenSHA) if uid != 0 { store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = accessTokenScope } Bearer PATs also set IsApiToken=true and ApiTokenScope, but ctx.IsBasicAuth remains false because the selected auth method is OAuth2/Bearer rather than Basic. The scope is therefore available but ignored. PoC This test creates a token for user2 with only read:notification, then requests Git Smart HTTP refs for user2/repo2, which is private. The same token is rejected over Basic auth, but succeeds over Bearer auth. func TestPOCGitSmartHTTPBearerTokenBypassesRepositoryScope(t *testing.T) { defer tests.PrepareTestEnv(t)() repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerName: "user2", Name: "repo2"}) assert.True(t, repo.IsPrivate) session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadNotification) url := "/user2/repo2/info/refs?service=git-upload-pack" basicReq := NewRequest(t, "GET", url) basicReq.SetBasicAuth(token, "x-oauth-basic") MakeRequest(t, basicReq, http.StatusForbidden) bearerReq := NewRequest(t, "GET", url).AddTokenAuth(token) resp := MakeRequest(t, bearerReq, http.StatusOK) assert.Contains(t, resp.Body.String(), "refs/heads/master") } Impact Any Gitea instance exposing Git Smart HTTP is affected when users use PATs or OAuth2 tokens as Bearer tokens. The attacker still needs a token for a user who has normal repository RBAC, so this does not grant access to repositories the token owner could not otherwise access. The vulnerability breaks the access-token scope boundary. A token intended only for unrelated scopes, such as read:notification, can clone or fetch private repository contents over Git Smart HTTP. The same root cause can affect write flows because git-receive-pack also calls the same repository scope check before normal write RBAC. Severity High 8.1/ 10 CVSS v3 base metrics Attack vector Network Attack complexity Low Privileges required Low User interaction None Scope Unchanged Confidentiality High Integrity High Availability None CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N CVE ID CVE-2026-28744 Weaknesses Weakness CWE-863 Credits @ohxorud-dev ohxorud-dev Reporter @lunny lunny Remediation developer _____________________________________________________________________ Token scope bypass on web archive download endpoint (variant of PR #37698) Moderate lunny published GHSA-cr4g-f395-h25h Jun 6, 2026 Package code.gitea.io/gitea (Go) Affected versions <= 1.26.1 Patched versions 1.26.2 Description Summary PR #37698 added checkDownloadTokenScope to /raw/, /media/, and attachment download web endpoints. The /archive/* endpoint (repo.Download in routers/web/repo/repo.go:372) was not included in the fix. This endpoint accepts OAuth2 tokens via webAuth.AllowOAuth2 (registered at routers/web/web.go:1649-1652) but does not call checkDownloadTokenScope or CheckRepoScopedToken. A personal access token with any non-repository scope (e.g., read:issue or read:misc) can download full repository archives (zip/tar.gz) of private repositories the token owner has access to. Impact Scope escalation: tokens scoped to non-repository categories can access full repository content through the archive download endpoint. Higher impact than endpoints fixed in #37698 because /archive/* serves the entire repository. Steps to Reproduce Create a personal access token with ONLY read:misc scope Access: GET /{owner}/{private-repo}/archive/main.tar.gz Archive is served (200 OK) instead of being rejected (403 Forbidden) Compare with fixed endpoints: GET /{owner}/{private-repo}/raw/branch/main/README.md correctly returns 403 Root Cause Download function in routers/web/repo/repo.go:372 does not call checkDownloadTokenScope. The outer group middleware reqUnitCodeReader checks repository permission but not token scope. The API equivalent (/api/v1/repos/{owner}/{repo}/archive/*) IS properly scoped via tokenRequiresScopes(AccessTokenScopeCategoryRepository). The git HTTP endpoints are scoped via CheckRepoScopedToken in httpBase. Suggested Fix Add checkDownloadTokenScope(ctx) to Download and InitiateDownload in routers/web/repo/repo.go. The function already exists in routers/web/repo/download.go (same package). Discovery Method Variant analysis of PR #37698 — reviewed all web routes with webAuth.AllowOAuth2 middleware. Severity Moderate CVE ID CVE-2026-20706 Weaknesses No CWEs Credits @geoo115 geoo115 Reporter _____________________________________________________________________ Missing repository-unit authorization on issue-template API endpoints Moderate lunny published GHSA-3fwp-p5rj-2pxf Jun 6, 2026 Package code.gitea.io/gitea (Go) Affected versions <= 1.26.1 Patched versions 1.26.2 Description Summary Three Gitea API endpoints — GET /repos/{owner}/{repo}/issue_templates, GET /repos/{owner}/{repo}/issue_config and GET /repos/{owner}/{repo}/issue_config/validate — read files from the repository's Code default branch (.gitea/ISSUE_TEMPLATE/* and issue_config.yaml) and return their contents, but are registered without the reqRepoReader(unit.TypeCode) authorization middleware that every sibling Code-tree endpoint in the same route group carries. A user who has access to a private repository through any single repository unit (for example an organization team granted only the Issues unit, with no Code access) can therefore read the issue-template and issue-config files of that repository's Code tree, which their permission set should not expose. Root cause The three endpoints lack the unit guard routers/api/v1/api.go:1433-1437: m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates) m.Get("/issue_config", context.ReferencesGitRepo(), repo.GetIssueConfig) m.Get("/issue_config/validate", context.ReferencesGitRepo(), repo.ValidateIssueConfig) m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages) m.Get("/licenses", reqRepoReader(unit.TypeCode), repo.GetLicenses) context.ReferencesGitRepo() only opens the git repository — it performs no permission check. Every other endpoint in this group that reads Code-tree content is guarded with reqRepoReader(unit.TypeCode): /languages, /licenses, /contents/*, /file-contents, and /{ball_type:tarball|zipball|bundle}/* (api.go:1418-1445). The three issue-template endpoints are the only Code-tree readers in the group missing that guard. The enclosing group runs repoAssignment() (api.go:1446), whose access check is satisfied by HasAnyUnitAccessOrPublicAccess — i.e. access to any unit of the repository is sufficient to pass. Without a per-unit reqRepoReader, the handlers run for a caller who has no Code permission. The handlers return Code-tree file contents routers/api/v1/repo/repo.go: func GetIssueTemplates(ctx *context.APIContext) { // :1179 ret := issue.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ... ctx.JSON(http.StatusOK, ret.IssueTemplates) } func GetIssueConfig(ctx *context.APIContext) { // :1209 issueConfig, _ := issue.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ctx.JSON(http.StatusOK, issueConfig) } ParseTemplatesFromDefaultBranch / GetTemplateConfigFromDefaultBranch read .gitea/ISSUE_TEMPLATE/* and issue_config.yaml from the default (Code) branch and return them in the JSON response. Proof of Concept victim-org/private-repo is a private repository. The attacker is a member of an organization team granted access to that repository through a non-Code unit only (e.g. the Issues unit) — a supported Gitea permission configuration. GET /api/v1/repos/victim-org/private-repo/issue_templates HTTP/1.1 Host: TARGET Authorization: token The response is 200 OK with the parsed contents of the repository's .gitea/ISSUE_TEMPLATE/* files. The same applies to /issue_config. Because the caller lacks the Code unit, every other Code-tree endpoint (/contents, /languages, …) correctly returns 404/403 for the same token — only these three return data. Impact A repository collaborator whose granted permissions exclude the Code unit can read the issue-template and issue-config files from the Code default branch of a private repository. The exposure is limited to those specific configuration files (not arbitrary Code-tree content), which is why this is rated low impact. It is nonetheless a unit-level authorization bypass: the endpoints disclose Code-unit content to callers the permission model is meant to exclude. Suggested fix Add the same unit guard the sibling endpoints use, in routers/api/v1/api.go: m.Get("/issue_templates", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.GetIssueTemplates) m.Get("/issue_config", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.GetIssueConfig) m.Get("/issue_config/validate", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(), repo.ValidateIssueConfig) (If issue templates are intended to be visible to Issues-unit users for issue creation, reqRepoReader(unit.TypeIssues) is the appropriate guard — but the current absence of any unit guard is the bug.) References CWE-862 Missing Authorization CWE-284 Improper Access Control OWASP A01:2021 Broken Access Control Severity Moderate 4.3/ 10 CVSS v3 base metrics Attack vector Network Attack complexity Low Privileges required Low User interaction None Scope Unchanged Confidentiality Low Integrity None Availability None CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N CVE ID CVE-2026-27783 Weaknesses Weakness CWE-862 Credits @hoangperry hoangperry Reporter ========================================================= + CERT-RENATER | tel : 01-53-94-20-44 + + 23/25 Rue Daviel | fax : 01-53-94-20-41 + + 75013 Paris | email:cert@support.renater.fr + =========================================================