Skip to content

fix: enforce public-only token scope and harden push options / locale parsing#38323

Draft
bircni wants to merge 4 commits into
go-gitea:mainfrom
bircni:fix/security-token-scope-and-dos
Draft

fix: enforce public-only token scope and harden push options / locale parsing#38323
bircni wants to merge 4 commits into
go-gitea:mainfrom
bircni:fix/security-token-scope-and-dos

Conversation

@bircni

@bircni bircni commented Jul 3, 2026

Copy link
Copy Markdown
Member

Three independent security hardening fixes, each with a regression test:

  • Locale DoS: the Locale middleware passed the raw Accept-Language header to ParseAcceptLanguage, whose guard only counts - while the scanner aliases _ to - — a large _-separated header on an unauthenticated request burned CPU. The header is now length-bounded before parsing.
  • Public-only token scope: GET /teams/{id}/repos, .../repos/{org}/{repo}, /teams/{id}/activities/feeds, and /users/{username}/orgs/{org}/permissions still returned private repo/activity/permission data to a public-only token. They now filter via TokenCanAccessRepo / ApplyPublicOnly and reject non-public org permissions.
  • Push-option visibility: repo.private / repo.template push options were applied to any existing repo, letting an owner/admin silently flip visibility bypassing audit, webhooks, and notifications. They are now honored only on push-to-create.

bircni added 3 commits July 3, 2026 19:51
The Locale middleware runs on every unauthenticated request and passed the
raw Accept-Language header to language.ParseAcceptLanguage. That parser has
quadratic-time behavior on long malformed inputs; its guard only counts "-"
separators while the scanner aliases "_" to "-", so a single unauthenticated
request with a large "_"-separated header burns seconds of CPU. Bound the
header length before parsing (only the leading languages are used anyway).
…endpoints

A public-only access token could still read private data through routes whose
handlers did not apply the restriction:

- GET /api/v1/teams/{id}/repos and .../repos/{org}/{repo} returned private team
  repository metadata (the doer's own access was checked, but not the token's
  public-only scope).
- GET /api/v1/teams/{id}/activities/feeds returned private activity entries.
- GET /api/v1/users/{username}/orgs/{org}/permissions disclosed membership
  permissions for a non-public org.

Filter repos via TokenCanAccessRepo, apply ApplyPublicOnly to the team feed, and
reject public-only access to non-public org permissions.
…-to-create

The post-receive hook applied the repo.private and repo.template git push
options to any existing repository, letting a repo owner or admin collaborator
silently toggle visibility with a bare "git push -o repo.private=..." while
bypassing the audit trail, webhook, and notifications a settings change fires.
These options are only meant to set the initial state during push-to-create, so
skip them once the repository is populated.
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 3, 2026
@bircni bircni added the backport/v1.27 This PR should be backported to Gitea 1.27 label Jul 3, 2026
@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Jul 5, 2026
}

// FIXME: these options are not quite right, for example: changing visibility should do more works than just setting the is_private flag
// These options should only be used for "push-to-create"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"FIXME"

Comment thread routers/private/hook_post_receive.go Outdated
Comment on lines 165 to 185

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If "push-to-create" only, do these "if" blocks still make sense?

Comment thread routers/private/hook_post_receive.go Outdated
Comment on lines 165 to 185

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If "push-to-create" only, do these "if" blocks still make sense?

Comment on lines +124 to +125
var repos []api.Repository
DecodeJSON(t, resp, &repos)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can AI learn correct code pattern?

Comment thread tests/integration/git_push_test.go Outdated
Comment on lines +155 to +157
defer func() {
require.NoError(t, repo_service.DeleteRepositoryDirectly(t.Context(), repo.ID))
}()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not "clean up"

@bircni bircni marked this pull request as draft July 5, 2026 15:38
Comment thread routers/private/hook_post_receive.go Outdated
Comment on lines +163 to +167
// These options are only meant for "push-to-create": setting the initial
// visibility/template flags on a repository created by the very first push.
// On an already-populated repository a bare "git push -o repo.private=..."
// would silently flip visibility without an audit entry, webhook, or
// notification, so restrict the options to the push-to-create case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment seems not quite right.

It not only works for "push-to-create", it also works for all empty repo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/v1.27 This PR should be backported to Gitea 1.27 lgtm/need 1 This PR needs approval from one additional maintainer to be merged. type/bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants