diff --git a/urls.go b/urls.go index 01f179f..70e9a5c 100644 --- a/urls.go +++ b/urls.go @@ -30,6 +30,9 @@ import ( "strings" ) +// Max length of the scpUrl to prevent reDOS attacks +const maxLen = 1000 + var ( // scpSyntax was modified from https://golang.org/src/cmd/go/vcs.go. scpSyntax = regexp.MustCompile(`^([a-zA-Z0-9-._~]+@)?([a-zA-Z0-9._-]+):([a-zA-Z0-9./._-]+)(?:\?||$)(.*)$`) @@ -90,6 +93,9 @@ func ParseTransport(rawurl string) (*url.URL, error) { // ParseScp parses rawurl into a URL object. The rawurl must be // an SCP-like URL, otherwise ParseScp returns an error. func ParseScp(rawurl string) (*url.URL, error) { + if len(rawurl) > maxLen { + return nil, fmt.Errorf("URL too long: %q", rawurl) + } match := scpSyntax.FindAllStringSubmatch(rawurl, -1) if len(match) == 0 { return nil, fmt.Errorf("no scp URL found in %q", rawurl) diff --git a/urls_test.go b/urls_test.go index d4f1f72..f882add 100644 --- a/urls_test.go +++ b/urls_test.go @@ -218,3 +218,11 @@ func TestParse(t *testing.T) { } } } + +func TestTooLong(t *testing.T) { + longUrl := "https://example.com/" + strings.Repeat("a", 2048) + _, err := ParseScp(longUrl) + if err == nil { + t.Errorf("Parse(%q) = nil, want error", longUrl) + } +}