number of cookies. To avoid denial of service attacks, this setting and default
was backported to Go 1.25.2 and Go 1.24.8.
+Go 1.26 added a new `urlmaxqueryparams` setting that controls the maximum number
+of query parameters that net/url will accept when parsing a URL-encoded query string.
+If the number of parameters exceeds the number set in `urlmaxqueryparams`,
+parsing will fail early. The default value is `urlmaxqueryparams=10000`.
+Setting `urlmaxqueryparams=0`bles the limit. To avoid denial of service attacks,
+this setting and default was backported to Go 1.25.4 and Go 1.24.10.
+
Go 1.26 added a new `urlstrictcolons` setting that controls whether `net/url.Parse`
allows malformed hostnames containing colons outside of a bracketed IPv6 address.
The default `urlstrictcolons=1` rejects URLs such as `http://localhost:1:2` or `http://::1/`.
{Name: "tlssha1", Package: "crypto/tls", Changed: 25, Old: "1"},
{Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"},
{Name: "updatemaxprocs", Package: "runtime", Changed: 25, Old: "0"},
+ {Name: "urlmaxqueryparams", Package: "net/url", Changed: 24, Old: "0"},
{Name: "urlstrictcolons", Package: "net/url", Changed: 26, Old: "0"},
{Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"},
{Name: "winsymlink", Package: "os", Changed: 23, Old: "0"},
return m, err
}
+var urlmaxqueryparams = godebug.New("urlmaxqueryparams")
+
+const defaultMaxParams = 10000
+
+func urlParamsWithinMax(params int) bool {
+ withinDefaultMax := params <= defaultMaxParams
+ if urlmaxqueryparams.Value() == "" {
+ return withinDefaultMax
+ }
+ customMax, err := strconv.Atoi(urlmaxqueryparams.Value())
+ if err != nil {
+ return withinDefaultMax
+ }
+ withinCustomMax := customMax == 0 || params < customMax
+ if withinDefaultMax != withinCustomMax {
+ urlmaxqueryparams.IncNonDefault()
+ }
+ return withinCustomMax
+}
+
func parseQuery(m Values, query string) (err error) {
+ if !urlParamsWithinMax(strings.Count(query, "&") + 1) {
+ return errors.New("number of URL query parameters exceeded limit")
+ }
for query != "" {
var key string
key, query, _ = strings.Cut(query, "&")
}
}
+func TestParseQueryLimits(t *testing.T) {
+ for _, test := range []struct {
+ params int
+ godebug string
+ wantErr bool
+ }{{
+ params: 10,
+ wantErr: false,
+ }, {
+ params: defaultMaxParams,
+ wantErr: false,
+ }, {
+ params: defaultMaxParams + 1,
+ wantErr: true,
+ }, {
+ params: 10,
+ godebug: "urlmaxqueryparams=9",
+ wantErr: true,
+ }, {
+ params: defaultMaxParams + 1,
+ godebug: "urlmaxqueryparams=0",
+ wantErr: false,
+ }} {
+ t.Setenv("GODEBUG", test.godebug)
+ want := Values{}
+ var b strings.Builder
+ for i := range test.params {
+ if i > 0 {
+ b.WriteString("&")
+ }
+ p := fmt.Sprintf("p%v", i)
+ b.WriteString(p)
+ want[p] = []string{""}
+ }
+ query := b.String()
+ got, err := ParseQuery(query)
+ if gotErr, wantErr := err != nil, test.wantErr; gotErr != wantErr {
+ t.Errorf("GODEBUG=%v ParseQuery(%v params) = %v, want error: %v", test.godebug, test.params, err, wantErr)
+ }
+ if err != nil {
+ continue
+ }
+ if got, want := len(got), test.params; got != want {
+ t.Errorf("GODEBUG=%v ParseQuery(%v params): got %v params, want %v", test.godebug, test.params, got, want)
+ }
+ }
+}
+
type RequestURITest struct {
url *URL
out string
The number of non-default behaviors executed by the runtime
package due to a non-default GODEBUG=updatemaxprocs=... setting.
+ /godebug/non-default-behavior/urlmaxqueryparams:events
+ The number of non-default behaviors executed by the net/url
+ package due to a non-default GODEBUG=urlmaxqueryparams=...
+ setting.
+
/godebug/non-default-behavior/urlstrictcolons:events
The number of non-default behaviors executed by the net/url
package due to a non-default GODEBUG=urlstrictcolons=...