@@ -545,6 +545,9 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
545
545
return nil , host , nil
546
546
}
547
547
userinfo := authority [:i ]
548
+ if ! validUserinfo (userinfo ) {
549
+ return nil , "" , errors .New ("net/url: invalid userinfo" )
550
+ }
548
551
if ! strings .Contains (userinfo , ":" ) {
549
552
if userinfo , err = unescape (userinfo , encodeUserPassword ); err != nil {
550
553
return nil , "" , err
@@ -1051,3 +1054,33 @@ func (u *URL) UnmarshalBinary(text []byte) error {
1051
1054
* u = * u1
1052
1055
return nil
1053
1056
}
1057
+
1058
+ // validUserinfo reports whether s is a valid userinfo string per RFC 3986
1059
+ // Section 3.2.1:
1060
+ // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
1061
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1062
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1063
+ // / "*" / "+" / "," / ";" / "="
1064
+ //
1065
+ // It doesn't validate pct-encoded. The caller does that via func unescape.
1066
+ func validUserinfo (s string ) bool {
1067
+ for _ , r := range s {
1068
+ if 'A' <= r && r <= 'Z' {
1069
+ continue
1070
+ }
1071
+ if 'a' <= r && r <= 'z' {
1072
+ continue
1073
+ }
1074
+ if '0' <= r && r <= '9' {
1075
+ continue
1076
+ }
1077
+ switch r {
1078
+ case '-' , '.' , '_' , ':' , '~' , '!' , '$' , '&' , '\'' ,
1079
+ '(' , ')' , '*' , '+' , ',' , ';' , '=' , '%' , '@' :
1080
+ continue
1081
+ default :
1082
+ return false
1083
+ }
1084
+ }
1085
+ return true
1086
+ }
0 commit comments