mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-16 15:48:55 +02:00
Addresses a batch of privately reported security issues, grouped by area: - **SSRF** - migration PR-patch/asset fetches, OAuth2 avatar & OpenID discovery, pull-mirror URL re-validation, and the outbound proxy path. - **Access-token scope** - prevent scope escalation on token creation; keep public-only tokens confined (feeds, packages, Actions listings, star/watch lists, limited/private owners). - **Access control / disclosure** - go-get default-branch leak, webhook authorization-header leak, watch clearing on private transitions, label/attachment scoping. - **Denial of service** - input bounds for npm dist-tags, Debian control files, Arch file lists, and SSH keys. ### 📌 Attention for site admins Not breaking - existing configs keep working - but two changes are worth a look: - **New SSRF protection** Outbound requests (migrations, OAuth2 avatars, OpenID discovery, pull mirrors, proxy path) are now validated against the allow/block host lists. If your instance legitimately reaches internal hosts, you may need to add them to `[security].ALLOWED_HOST_LIST` (and the relevant `ALLOW_LOCALNETWORKS` settings). - **Deprecation** `[webhook].ALLOWED_HOST_LIST` is deprecated and will be removed in a future release. Use `[security].ALLOWED_HOST_LIST` instead; the old key still works for now. --------- Co-authored-by: TheFox0x7 <thefox0x7@gmail.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Zettat123 <zettat123@gmail.com>
70 lines
2.1 KiB
Go
70 lines
2.1 KiB
Go
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package uri
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestReadURI(t *testing.T) {
|
|
p, err := filepath.Abs("./uri.go")
|
|
assert.NoError(t, err)
|
|
f, err := Open("file://" + p)
|
|
assert.NoError(t, err)
|
|
defer f.Close()
|
|
}
|
|
|
|
// TestOpenWithClientValidatesRedirectTarget verifies OpenWithClient routes the
|
|
// whole request chain (including redirects) through the provided client, so a
|
|
// client whose transport refuses to dial an internal target blocks a redirect to
|
|
// it — whereas the default client (old Open behavior) follows it.
|
|
func TestOpenWithClientValidatesRedirectTarget(t *testing.T) {
|
|
var internalHit atomic.Bool
|
|
internal := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
internalHit.Store(true)
|
|
_, _ = w.Write([]byte("secret"))
|
|
}))
|
|
defer internal.Close()
|
|
|
|
front := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, internal.URL, http.StatusFound)
|
|
}))
|
|
defer front.Close()
|
|
|
|
internalAddr := strings.TrimPrefix(internal.URL, "http://")
|
|
|
|
// a client that refuses to dial the internal target, mimicking the migration
|
|
// hostmatcher dialer that re-validates every hop
|
|
blockingClient := &http.Client{Transport: &http.Transport{
|
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
if addr == internalAddr {
|
|
return nil, errors.New("blocked internal address")
|
|
}
|
|
return (&net.Dialer{}).DialContext(ctx, network, addr)
|
|
},
|
|
}}
|
|
|
|
_, err := OpenWithClient(front.URL, blockingClient)
|
|
require.Error(t, err)
|
|
assert.False(t, internalHit.Load(), "the redirect target must not be reached through the validating client")
|
|
|
|
// the default client (the previous behavior) follows the redirect to the internal target
|
|
internalHit.Store(false)
|
|
rc, err := Open(front.URL)
|
|
require.NoError(t, err)
|
|
_ = rc.Close()
|
|
assert.True(t, internalHit.Load(), "sanity check: the default client follows the redirect")
|
|
}
|