@@ -563,6 +563,9 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
563
563
return nil , host , nil
564
564
}
565
565
userinfo := authority [:i ]
566
+ if ! validUserinfo (userinfo ) {
567
+ return nil , "" , errors .New ("net/url: invalid userinfo" )
568
+ }
566
569
if ! strings .Contains (userinfo , ":" ) {
567
570
if userinfo , err = unescape (userinfo , encodeUserPassword ); err != nil {
568
571
return nil , "" , err
@@ -1069,3 +1072,33 @@ func (u *URL) UnmarshalBinary(text []byte) error {
1069
1072
* u = * u1
1070
1073
return nil
1071
1074
}
1075
+
1076
+ // validUserinfo reports whether s is a valid userinfo string per RFC 3986
1077
+ // Section 3.2.1:
1078
+ // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
1079
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1080
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1081
+ // / "*" / "+" / "," / ";" / "="
1082
+ //
1083
+ // It doesn't validate pct-encoded. The caller does that via func unescape.
1084
+ func validUserinfo (s string ) bool {
1085
+ for _ , r := range s {
1086
+ if 'A' <= r && r <= 'Z' {
1087
+ continue
1088
+ }
1089
+ if 'a' <= r && r <= 'z' {
1090
+ continue
1091
+ }
1092
+ if '0' <= r && r <= '9' {
1093
+ continue
1094
+ }
1095
+ switch r {
1096
+ case '-' , '.' , '_' , ':' , '~' , '!' , '$' , '&' , '\'' ,
1097
+ '(' , ')' , '*' , '+' , ',' , ';' , '=' , '%' , '@' :
1098
+ continue
1099
+ default :
1100
+ return false
1101
+ }
1102
+ }
1103
+ return true
1104
+ }
0 commit comments