@@ -124,17 +124,17 @@ func validateURL(rawURL string) error {
124124// validateGitHubPRURL performs strict validation for GitHub PR URLs used in auto-opening.
125125// This ensures the URL follows the exact pattern: https://github.com/{owner}/{repo}/pull/{number}
126126// with no additional path segments, fragments, or suspicious characters.
127- // The URL may optionally have ?goose=1 parameter which we add for tracking.
127+ // The URL may optionally have ?goose=<action> parameter which we add for tracking.
128128func validateGitHubPRURL (rawURL string ) error {
129129 // First do basic URL validation
130130 if err := validateURL (rawURL ); err != nil {
131131 return err
132132 }
133133
134- // Strip the ?goose=1 parameter if present for pattern validation
134+ // Strip the ?goose parameter if present for pattern validation
135135 urlToValidate := rawURL
136- if strings .HasSuffix (rawURL , "?goose=1" ) {
137- urlToValidate = strings . TrimSuffix ( rawURL , "?goose=1" )
136+ if idx := strings .Index (rawURL , "?goose=" ); idx != - 1 {
137+ urlToValidate = rawURL [: idx ]
138138 }
139139
140140 // Check against strict GitHub PR URL pattern
@@ -149,19 +149,34 @@ func validateGitHubPRURL(rawURL string) error {
149149 }
150150
151151 // Reject URLs with URL encoding (could hide malicious content)
152- // Exception: %3D which is = in URL encoding, only as part of ?goose=1
153- if strings .Contains (rawURL , "%" ) && ! strings .HasSuffix (rawURL , "?goose%3D1" ) {
154- return errors .New ("URL contains encoded characters" )
152+ // Exception: %3D which is = in URL encoding, only as part of ?goose parameter
153+ if strings .Contains (rawURL , "%" ) {
154+ // Allow URL encoding only in the goose parameter value
155+ if idx := strings .Index (rawURL , "?goose=" ); idx != - 1 {
156+ // Check if encoding is only in the goose parameter
157+ if strings .Contains (rawURL [:idx ], "%" ) {
158+ return errors .New ("URL contains encoded characters outside goose parameter" )
159+ }
160+ } else {
161+ return errors .New ("URL contains encoded characters" )
162+ }
155163 }
156164
157165 // Reject URLs with fragments
158166 if strings .Contains (rawURL , "#" ) {
159167 return errors .New ("URL contains fragments" )
160168 }
161169
162- // Allow only ?goose=1 query parameter, nothing else
163- if strings .Contains (rawURL , "?" ) && ! strings .HasSuffix (rawURL , "?goose=1" ) && ! strings .HasSuffix (rawURL , "?goose%3D1" ) {
164- return errors .New ("URL contains unexpected query parameters" )
170+ // Allow only ?goose=<value> query parameter, nothing else
171+ if strings .Contains (rawURL , "?" ) {
172+ // Check if it's the goose parameter
173+ if idx := strings .Index (rawURL , "?goose=" ); idx == - 1 {
174+ return errors .New ("URL contains unexpected query parameters" )
175+ }
176+ // Ensure no additional parameters after goose
177+ if strings .Contains (rawURL [strings .Index (rawURL , "?goose=" )+ 7 :], "&" ) {
178+ return errors .New ("URL contains additional query parameters" )
179+ }
165180 }
166181
167182 // Reject URLs with double slashes (except after https:)
0 commit comments