diff --git a/sink.go b/sink.go index 499772a00..88b5ba704 100644 --- a/sink.go +++ b/sink.go @@ -103,8 +103,10 @@ func (sr *sinkRegistry) newSink(rawURL string) (Sink, error) { if err != nil { return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err) } + + // No scheme specified. Assume absolute or relative file path. if u.Scheme == "" { - u.Scheme = schemeFile + return sr.newFileSinkFromPath(rawURL) } sr.mu.Lock() @@ -145,6 +147,10 @@ func (sr *sinkRegistry) newFileSinkFromURL(u *url.URL) (Sink, error) { return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u) } + if strings.Contains(u.Path, "..") { + return nil, fmt.Errorf("file URLs must not contain '..': got %v", u) + } + return sr.newFileSinkFromPath(u.Path) } diff --git a/writer_test.go b/writer_test.go index 20e00b74b..4f1d81f17 100644 --- a/writer_test.go +++ b/writer_test.go @@ -224,6 +224,36 @@ func TestOpenOtherErrors(t *testing.T) { } } +func TestOpenDoubleDotSegmentsDisallowed(t *testing.T) { + tests := []struct { + msg string + paths []string + wantErr string + }{ + { + msg: "invalid double dot as the host element", + paths: []string{ + "file://../some/path", + }, + wantErr: `open sink "file://../some/path": file URLs must leave host empty or use localhost: got file://../some/path`, + }, + { + msg: "double dot segments not allowed", + paths: []string{ + "file:///../../../yoursecret", + }, + wantErr: `open sink "file:///../../../yoursecret": file URLs must not contain '..': got file:///../../../yoursecret`, + }, + } + + for _, tt := range tests { + t.Run(tt.msg, func(t *testing.T) { + _, _, err := Open(tt.paths...) + assert.EqualError(t, err, tt.wantErr) + }) + } +} + type testWriter struct { expected string t testing.TB