diff --git a/internal/pipeline/events_api.go b/internal/pipeline/events_api.go index c52b2a0..14a0fe2 100644 --- a/internal/pipeline/events_api.go +++ b/internal/pipeline/events_api.go @@ -19,6 +19,8 @@ package pipeline import ( "net/http" + "path/filepath" + "strings" "github.com/moov-io/base/log" @@ -49,6 +51,11 @@ func (fr *FileReceiver) manuallyProduceFileUploaded() http.HandlerFunc { w.WriteHeader(http.StatusBadRequest) return } + // Reject paths which are trying to traverse the filesystem + if strings.Contains(dir, "..") || filepath.IsAbs(dir) { + w.WriteHeader(http.StatusBadRequest) + return + } matches, err := m.getNonCanceledMatches(dir) if err != nil { diff --git a/internal/pipeline/events_api_test.go b/internal/pipeline/events_api_test.go index 6f99226..4974b92 100644 --- a/internal/pipeline/events_api_test.go +++ b/internal/pipeline/events_api_test.go @@ -147,4 +147,18 @@ func TestEventsAPI_FileUploadedErrors(t *testing.T) { defer resp.Body.Close() require.Equal(t, http.StatusNotFound, resp.StatusCode) }) + + t.Run("Call /file-uploaded on insecure paths", func(t *testing.T) { + paths := []string{"../../etc/passwd", "/etc/passwd"} + for i := range paths { + address := fmt.Sprintf("http://%s/shards/testing/pipeline/%s/file-uploaded", adminServer.BindAddr(), paths[i]) + req, err := http.NewRequest("PUT", address, nil) + require.NoError(t, err, fmt.Sprintf("on address %s", address)) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusNotFound, resp.StatusCode, fmt.Sprintf("on address %s", address)) + } + }) + }